Add Model SDF generation utilities
This commit is contained in:
@@ -291,6 +291,18 @@ namespace FlaxEditor.Content.Import
|
||||
[EditorOrder(420), DefaultValue(true), EditorDisplay("Materials", "Restore Materials On Reimport"), Tooltip("If checked, the importer will try to restore the assigned materials to the model slots.")]
|
||||
public bool RestoreMaterialsOnReimport { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, enables generation of Signed Distance Field (SDF).
|
||||
/// </summary>
|
||||
[EditorOrder(1500), DefaultValue(false), EditorDisplay("SDF"), VisibleIf(nameof(Type_Model))]
|
||||
public bool GenerateSDF { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Resolution scale for generated Signed Distance Field (SDF) texture. Higher values improve accuracy but increase memory usage and reduce performance.
|
||||
/// </summary>
|
||||
[EditorOrder(1510), DefaultValue(1.0f), Limit(0.0001f, 100.0f), EditorDisplay("SDF"), VisibleIf(nameof(Type_Model))]
|
||||
public float SDFResolution { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported mesh/animations are splitted into separate assets. Used if ObjectIndex is set to -1.
|
||||
/// </summary>
|
||||
@@ -303,6 +315,8 @@ namespace FlaxEditor.Content.Import
|
||||
[EditorOrder(2010), DefaultValue(-1), EditorDisplay("Splitting"), Tooltip("The zero-based index for the mesh/animation clip to import. If the source file has more than one mesh/animation it can be used to pick a desire object. Default -1 imports all objects.")]
|
||||
public int ObjectIndex { get; set; } = -1;
|
||||
|
||||
private bool Type_Model => Type == ModelType.Model;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
@@ -350,6 +364,10 @@ namespace FlaxEditor.Content.Import
|
||||
public byte ImportTextures;
|
||||
public byte RestoreMaterialsOnReimport;
|
||||
|
||||
// SDF
|
||||
public byte GenerateSDF;
|
||||
public float SDFResolution;
|
||||
|
||||
// Splitting
|
||||
public byte SplitObjects;
|
||||
public int ObjectIndex;
|
||||
@@ -392,6 +410,8 @@ namespace FlaxEditor.Content.Import
|
||||
ImportMaterials = (byte)(ImportMaterials ? 1 : 0),
|
||||
ImportTextures = (byte)(ImportTextures ? 1 : 0),
|
||||
RestoreMaterialsOnReimport = (byte)(RestoreMaterialsOnReimport ? 1 : 0),
|
||||
GenerateSDF = (byte)(GenerateSDF ? 1 : 0),
|
||||
SDFResolution = SDFResolution,
|
||||
SplitObjects = (byte)(SplitObjects ? 1 : 0),
|
||||
ObjectIndex = ObjectIndex,
|
||||
};
|
||||
@@ -431,25 +451,22 @@ namespace FlaxEditor.Content.Import
|
||||
ImportMaterials = options.ImportMaterials != 0;
|
||||
ImportTextures = options.ImportTextures != 0;
|
||||
RestoreMaterialsOnReimport = options.RestoreMaterialsOnReimport != 0;
|
||||
GenerateSDF = options.GenerateSDF != 0;
|
||||
SDFResolution = options.SDFResolution;
|
||||
SplitObjects = options.SplitObjects != 0;
|
||||
ObjectIndex = options.ObjectIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the restore the asset import options from the target resource file.
|
||||
/// Tries the restore the asset import options from the target resource file. Applies the project default options too.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="assetPath">The asset path.</param>
|
||||
/// <returns>True settings has been restored, otherwise false.</returns>
|
||||
public static bool TryRestore(ref ModelImportSettings options, string assetPath)
|
||||
public static void TryRestore(ref ModelImportSettings options, string assetPath)
|
||||
{
|
||||
if (ModelImportEntry.Internal_GetModelImportOptions(assetPath, out var internalOptions))
|
||||
{
|
||||
// Restore settings
|
||||
options.FromInternal(ref internalOptions);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
ModelImportEntry.Internal_GetModelImportOptions(assetPath, out var internalOptions);
|
||||
options.FromInternal(ref internalOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +512,7 @@ namespace FlaxEditor.Content.Import
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -16,26 +16,6 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// </summary>
|
||||
public readonly Button Button = new Button();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the element.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
public void Init(string text)
|
||||
{
|
||||
Button.Text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the element.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
public void Init(string text, Color color)
|
||||
{
|
||||
Button.Text = text;
|
||||
Button.SetColors(color);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Control Control => Button;
|
||||
}
|
||||
|
||||
@@ -133,11 +133,13 @@ namespace FlaxEditor.CustomEditors
|
||||
/// Adds new button element.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="tooltip">The tooltip text.</param>
|
||||
/// <returns>The created element.</returns>
|
||||
public ButtonElement Button(string text)
|
||||
public ButtonElement Button(string text, string tooltip = null)
|
||||
{
|
||||
var element = new ButtonElement();
|
||||
element.Init(text);
|
||||
element.Button.Text = text;
|
||||
element.Button.TooltipText = tooltip;
|
||||
OnAddElement(element);
|
||||
return element;
|
||||
}
|
||||
@@ -147,11 +149,14 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="tooltip">The tooltip text.</param>
|
||||
/// <returns>The created element.</returns>
|
||||
public ButtonElement Button(string text, Color color)
|
||||
public ButtonElement Button(string text, Color color, string tooltip = null)
|
||||
{
|
||||
ButtonElement element = new ButtonElement();
|
||||
element.Init(text, color);
|
||||
element.Button.Text = text;
|
||||
element.Button.TooltipText = tooltip;
|
||||
element.Button.SetColors(color);
|
||||
OnAddElement(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Level/Prefabs/Prefab.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Config/GraphicsSettings.h"
|
||||
#include "Engine/Core/Cache.h"
|
||||
#include "Engine/CSG/CSGBuilder.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
@@ -196,6 +197,10 @@ struct InternalModelOptions
|
||||
byte ImportTextures;
|
||||
byte RestoreMaterialsOnReimport;
|
||||
|
||||
// SDF
|
||||
byte GenerateSDF;
|
||||
float SDFResolution;
|
||||
|
||||
// Splitting
|
||||
byte SplitObjects;
|
||||
int32 ObjectIndex;
|
||||
@@ -235,6 +240,8 @@ struct InternalModelOptions
|
||||
to->ImportMaterials = from->ImportMaterials;
|
||||
to->ImportTextures = from->ImportTextures;
|
||||
to->RestoreMaterialsOnReimport = from->RestoreMaterialsOnReimport;
|
||||
to->GenerateSDF = from->GenerateSDF;
|
||||
to->SDFResolution = from->SDFResolution;
|
||||
to->SplitObjects = from->SplitObjects;
|
||||
to->ObjectIndex = from->ObjectIndex;
|
||||
}
|
||||
@@ -274,6 +281,8 @@ struct InternalModelOptions
|
||||
to->ImportMaterials = from->ImportMaterials;
|
||||
to->ImportTextures = from->ImportTextures;
|
||||
to->RestoreMaterialsOnReimport = from->RestoreMaterialsOnReimport;
|
||||
to->GenerateSDF = from->GenerateSDF;
|
||||
to->SDFResolution = from->SDFResolution;
|
||||
to->SplitObjects = from->SplitObjects;
|
||||
to->ObjectIndex = from->ObjectIndex;
|
||||
}
|
||||
@@ -626,22 +635,23 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
|
||||
static void GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
|
||||
{
|
||||
// Initialize defaults
|
||||
ImportModelFile::Options options;
|
||||
if (const auto* graphicsSettings = GraphicsSettings::Get())
|
||||
{
|
||||
options.GenerateSDF = graphicsSettings->GenerateSDFOnModelImport;
|
||||
}
|
||||
|
||||
// Get options from model
|
||||
String path;
|
||||
MUtils::ToString(pathObj, path);
|
||||
FileSystem::NormalizePath(path);
|
||||
ImportModelFile::TryGetImportOptions(path, options);
|
||||
|
||||
ImportModelFile::Options options;
|
||||
if (ImportModelFile::TryGetImportOptions(path, options))
|
||||
{
|
||||
// Convert into managed storage
|
||||
InternalModelOptions::Convert(&options, result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Convert into managed storage
|
||||
InternalModelOptions::Convert(&options, result);
|
||||
}
|
||||
|
||||
static bool GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result)
|
||||
@@ -852,7 +862,7 @@ public:
|
||||
continue;
|
||||
switch (e.Type)
|
||||
{
|
||||
// Keyboard events
|
||||
// Keyboard events
|
||||
case InputDevice::EventType::Char:
|
||||
window->OnCharInput(e.CharData.Char);
|
||||
break;
|
||||
@@ -862,7 +872,7 @@ public:
|
||||
case InputDevice::EventType::KeyUp:
|
||||
window->OnKeyUp(e.KeyData.Key);
|
||||
break;
|
||||
// Mouse events
|
||||
// Mouse events
|
||||
case InputDevice::EventType::MouseDown:
|
||||
window->OnMouseDown(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
|
||||
break;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
PreviewLight.ShadowsDistance = 2000.0f;
|
||||
Task.ViewFlags |= ViewFlags.Shadows;
|
||||
}
|
||||
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
@@ -75,10 +75,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnClean();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the highlight/isolate effects on UI.
|
||||
/// </summary>
|
||||
public void UpdateEffectsOnUI()
|
||||
private void UpdateEffectsOnUI()
|
||||
{
|
||||
Window._skipEffectsGuiEvents = true;
|
||||
|
||||
@@ -97,10 +94,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Window._skipEffectsGuiEvents = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the material slots UI parts. Should be called after material slot rename.
|
||||
/// </summary>
|
||||
public void UpdateMaterialSlotsUI()
|
||||
private void UpdateMaterialSlotsUI()
|
||||
{
|
||||
Window._skipEffectsGuiEvents = true;
|
||||
|
||||
@@ -123,12 +117,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Window._skipEffectsGuiEvents = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the material slot index to the mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="newSlotIndex">New index of the material slot to use.</param>
|
||||
public void SetMaterialSlot(Mesh mesh, int newSlotIndex)
|
||||
private void SetMaterialSlot(Mesh mesh, int newSlotIndex)
|
||||
{
|
||||
if (Window._skipEffectsGuiEvents)
|
||||
return;
|
||||
@@ -139,11 +128,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Window.MarkAsEdited();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the material slot to isolate.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public void SetIsolate(Mesh mesh)
|
||||
private void SetIsolate(Mesh mesh)
|
||||
{
|
||||
if (Window._skipEffectsGuiEvents)
|
||||
return;
|
||||
@@ -153,11 +138,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
UpdateEffectsOnUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the material slot index to highlight.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public void SetHighlight(Mesh mesh)
|
||||
private void SetHighlight(Mesh mesh)
|
||||
{
|
||||
if (Window._skipEffectsGuiEvents)
|
||||
return;
|
||||
@@ -169,6 +150,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private class ProxyEditor : ProxyEditorBase
|
||||
{
|
||||
private CustomEditors.Elements.IntegerValueElement _sdfModelLodIndex;
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var proxy = (MeshesPropertiesProxy)Values[0];
|
||||
@@ -198,6 +181,46 @@ namespace FlaxEditor.Windows.Assets
|
||||
};
|
||||
}
|
||||
|
||||
// SDF
|
||||
{
|
||||
var group = layout.Group("SDF");
|
||||
|
||||
var sdf = proxy.Asset.SDF;
|
||||
if (sdf.Texture != null)
|
||||
{
|
||||
var size = sdf.Texture.Size3;
|
||||
group.Label($"SDF Texture {size.X}x{size.Y}x{size.Z} ({Utilities.Utils.FormatBytesCount(sdf.Texture.MemoryUsage)})").AddCopyContextMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
group.Label("No SDF");
|
||||
}
|
||||
|
||||
var resolution = group.FloatValue("Resolution Scale", proxy.Window.Editor.CodeDocs.GetTooltip(typeof(ModelImportSettings), nameof(ModelImportSettings.SDFResolution)));
|
||||
resolution.FloatValue.MinValue = 0.0001f;
|
||||
resolution.FloatValue.MaxValue = 100.0f;
|
||||
resolution.FloatValue.Value = sdf.Texture != null ? sdf.ResolutionScale : 1.0f;
|
||||
resolution.FloatValue.BoxValueChanged += b => { proxy.Window._importSettings.SDFResolution = b.Value; };
|
||||
|
||||
var lodIndex = group.IntegerValue("LOD Index", "Index of the model Level of Detail to use for SDF data building. By default uses the lowest quality LOD for fast building.");
|
||||
lodIndex.IntValue.MinValue = 0;
|
||||
lodIndex.IntValue.MaxValue = lods.Length - 1;
|
||||
lodIndex.IntValue.Value = sdf.Texture != null ? sdf.LOD : 6;
|
||||
_sdfModelLodIndex = lodIndex;
|
||||
|
||||
var buttons = group.CustomContainer<UniformGridPanel>();
|
||||
var gridControl = buttons.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
gridControl.SlotsHorizontally = 2;
|
||||
gridControl.SlotsVertically = 1;
|
||||
var rebuildButton = buttons.Button("Rebuild", "Rebuilds the model SDF.").Button;
|
||||
rebuildButton.Clicked += OnRebuildSDF;
|
||||
var removeButton = buttons.Button("Remove", "Removes the model SDF data from the asset.").Button;
|
||||
removeButton.Enabled = sdf.Texture != null;
|
||||
removeButton.Clicked += OnRemoveSDF;
|
||||
}
|
||||
|
||||
// Group per LOD
|
||||
for (int lodIndex = 0; lodIndex < lods.Length; lodIndex++)
|
||||
{
|
||||
@@ -260,6 +283,22 @@ namespace FlaxEditor.Windows.Assets
|
||||
proxy.UpdateMaterialSlotsUI();
|
||||
}
|
||||
|
||||
private void OnRebuildSDF()
|
||||
{
|
||||
var proxy = (MeshesPropertiesProxy)Values[0];
|
||||
proxy.Asset.GenerateSDF(proxy.Window._importSettings.SDFResolution, _sdfModelLodIndex.Value);
|
||||
proxy.Window.MarkAsEdited();
|
||||
Presenter.BuildLayoutOnUpdate();
|
||||
}
|
||||
|
||||
private void OnRemoveSDF()
|
||||
{
|
||||
var proxy = (MeshesPropertiesProxy)Values[0];
|
||||
proxy.Asset.SetSDF(new ModelBase.SDFData());
|
||||
proxy.Window.MarkAsEdited();
|
||||
Presenter.BuildLayoutOnUpdate();
|
||||
}
|
||||
|
||||
internal override void RefreshInternal()
|
||||
{
|
||||
// Skip updates when model is not loaded
|
||||
@@ -645,14 +684,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
[CustomEditor(typeof(ProxyEditor))]
|
||||
private sealed class ImportPropertiesProxy : PropertiesProxyBase
|
||||
{
|
||||
private ModelImportSettings ImportSettings = new ModelImportSettings();
|
||||
private ModelImportSettings ImportSettings;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLoad(ModelWindow window)
|
||||
{
|
||||
base.OnLoad(window);
|
||||
|
||||
ModelImportSettings.TryRestore(ref ImportSettings, window.Item.Path);
|
||||
ImportSettings = window._importSettings;
|
||||
}
|
||||
|
||||
public void Reimport()
|
||||
@@ -675,7 +714,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
var group = layout.Group("Import Settings");
|
||||
|
||||
var importSettingsField = typeof(ImportPropertiesProxy).GetField("ImportSettings", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var importSettingsField = typeof(ImportPropertiesProxy).GetField(nameof(ImportSettings), BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
||||
group.Object(importSettingsValues);
|
||||
|
||||
@@ -730,6 +769,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
private readonly ModelPreview _preview;
|
||||
private StaticModel _highlightActor;
|
||||
private MeshDataCache _meshData;
|
||||
private ModelImportSettings _importSettings = new ModelImportSettings();
|
||||
|
||||
/// <inheritdoc />
|
||||
public ModelWindow(Editor editor, AssetItem item)
|
||||
@@ -868,6 +908,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
_refreshOnLODsLoaded = true;
|
||||
_preview.ViewportCamera.SetArcBallView(Asset.GetBox());
|
||||
ModelImportSettings.TryRestore(ref _importSettings, Item.Path);
|
||||
UpdateEffectsOnAsset();
|
||||
|
||||
// TODO: disable streaming for this model
|
||||
|
||||
Reference in New Issue
Block a user