Fix missing parameters metadata on nested material layers

#731
This commit is contained in:
Wojtek Figat
2024-09-09 12:34:18 +02:00
parent d939421c82
commit c62575612b
3 changed files with 100 additions and 131 deletions

View File

@@ -17,7 +17,7 @@ namespace FlaxEditor.Surface
public class MaterialSurface : VisjectSurface
{
/// <inheritdoc />
public MaterialSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
public MaterialSurface(IVisjectSurfaceOwner owner, Action onSave = null, FlaxEditor.Undo undo = null)
: base(owner, onSave, undo)
{
}

View File

@@ -73,9 +73,8 @@ namespace FlaxEditor.Surface
// By name
if (Editor.Instance.Options.Options.General.ScriptMembersOrder == GeneralOptions.MembersOrder.Alphabetical)
{
return string.Compare(x.DisplayName, y.DisplayName, StringComparison.InvariantCulture);
}
// Keep same order
return 0;
}
@@ -106,6 +105,79 @@ namespace FlaxEditor.Surface
}
}
private sealed class DummyMaterialSurfaceOwner : IVisjectSurfaceOwner
{
public Asset SurfaceAsset => null;
public string SurfaceName => null;
public FlaxEditor.Undo Undo => null;
public byte[] SurfaceData { get; set; }
public VisjectSurfaceContext ParentContext => null;
public void OnContextCreated(VisjectSurfaceContext context)
{
}
public void OnSurfaceEditedChanged()
{
}
public void OnSurfaceGraphEdited()
{
}
public void OnSurfaceClose()
{
}
}
private static void FindGraphParameters(Material material, List<SurfaceParameter> surfaceParameters)
{
if (material == null || material.WaitForLoaded())
return;
var surfaceData = material.LoadSurface(false);
if (surfaceData != null && surfaceData.Length > 0)
{
var surfaceOwner = new DummyMaterialSurfaceOwner { SurfaceData = surfaceData };
var surface = new MaterialSurface(surfaceOwner);
if (!surface.Load())
{
surfaceParameters.AddRange(surface.Parameters);
// Search for any nested parameters (eg. via Sample Layer)
foreach (var node in surface.Nodes)
{
if (node.GroupArchetype.GroupID == 8 && node.Archetype.TypeID == 1) // Sample Layer
{
if (node.Values != null && node.Values.Length > 0 && node.Values[0] is Guid layerId)
{
var layer = FlaxEngine.Content.Load<MaterialBase>(layerId);
if (layer)
{
FindGraphParameters(layer, surfaceParameters);
}
}
}
}
}
}
}
private static void FindGraphParameters(MaterialBase materialBase, List<SurfaceParameter> surfaceParameters)
{
while (materialBase != null && !materialBase.WaitForLoaded())
{
if (materialBase is MaterialInstance materialInstance)
{
materialBase = materialInstance.BaseMaterial;
}
else if (materialBase is Material material)
{
FindGraphParameters(material, surfaceParameters);
break;
}
}
}
internal static GraphParameterData[] InitGraphParameters(IEnumerable<MaterialParameter> parameters, Material material)
{
int count = parameters.Count();
@@ -113,128 +185,11 @@ namespace FlaxEditor.Surface
int i = 0;
// Load material surface parameters meta to use it for material instance parameters editing
SurfaceParameter[] surfaceParameters = null;
var surfaceParameters = new List<SurfaceParameter>();
try
{
Profiler.BeginEvent("Init Material Parameters UI Data");
if (material != null && !material.WaitForLoaded())
{
var surfaceData = material.LoadSurface(false);
if (surfaceData != null && surfaceData.Length > 0)
{
using (var memoryStream = new MemoryStream(surfaceData))
using (var stream = new BinaryReader(memoryStream))
{
// IMPORTANT! This must match C++ Graph format
// Magic Code
int tmp = stream.ReadInt32();
if (tmp != 1963542358)
{
// Error
throw new Exception("Invalid Graph format version");
}
// Version
var version = stream.ReadUInt32();
var guidBytes = new byte[16];
if (version < 7000)
{
// Time saved (not used anymore to prevent binary diffs after saving unmodified surface)
stream.ReadInt64();
// Nodes count
int nodesCount = stream.ReadInt32();
// Parameters count
int parametersCount = stream.ReadInt32();
// For each node
for (int j = 0; j < nodesCount; j++)
{
// ID
stream.ReadUInt32();
// Type
stream.ReadUInt16();
stream.ReadUInt16();
}
// For each param
surfaceParameters = new SurfaceParameter[parametersCount];
for (int j = 0; j < parametersCount; j++)
{
// Create param
var param = new SurfaceParameter();
surfaceParameters[j] = param;
// Properties
param.Type = new ScriptType(VisjectSurfaceContext.GetGraphParameterValueType((VisjectSurfaceContext.GraphParamType_Deprecated)stream.ReadByte()));
stream.Read(guidBytes, 0, 16);
param.ID = new Guid(guidBytes);
param.Name = stream.ReadStr(97);
param.IsPublic = stream.ReadByte() != 0;
var isStatic = stream.ReadByte() != 0;
var isUIVisible = stream.ReadByte() != 0;
var isUIEditable = stream.ReadByte() != 0;
// References [Deprecated]
int refsCount = stream.ReadInt32();
for (int k = 0; k < refsCount; k++)
stream.ReadUInt32();
// Value
stream.ReadCommonValue(ref param.Value);
// Meta
param.Meta.Load(stream);
}
}
else if (version == 7000)
{
// Nodes count
int nodesCount = stream.ReadInt32();
// Parameters count
int parametersCount = stream.ReadInt32();
// For each node
for (int j = 0; j < nodesCount; j++)
{
// ID
stream.ReadUInt32();
// Type
stream.ReadUInt16();
stream.ReadUInt16();
}
// For each param
surfaceParameters = new SurfaceParameter[parametersCount];
for (int j = 0; j < parametersCount; j++)
{
// Create param
var param = new SurfaceParameter();
surfaceParameters[j] = param;
// Properties
param.Type = stream.ReadVariantScriptType();
stream.Read(guidBytes, 0, 16);
param.ID = new Guid(guidBytes);
param.Name = stream.ReadStr(97);
param.IsPublic = stream.ReadByte() != 0;
// Value
param.Value = stream.ReadVariant();
// Meta
param.Meta.Load(stream);
}
}
}
}
}
FindGraphParameters(material, surfaceParameters);
}
catch (Exception ex)
{
@@ -248,7 +203,26 @@ namespace FlaxEditor.Surface
foreach (var parameter in parameters)
{
var surfaceParameter = surfaceParameters?.FirstOrDefault(x => x.ID == parameter.ParameterID);
var parameterId = parameter.ParameterID;
var surfaceParameter = surfaceParameters.FirstOrDefault(x => x.ID == parameterId);
if (surfaceParameter == null)
{
// Permutate original parameter ID to reflect logic in MaterialGenerator::prepareLayer used for nested layers
unsafe
{
var raw = parameterId;
var interop = *(FlaxEngine.Json.JsonSerializer.GuidInterop*)&raw;
interop.A -= (uint)(i * 17 + 13);
parameterId = *(Guid*)&interop;
}
surfaceParameter = surfaceParameters.FirstOrDefault(x => x.ID == parameterId);
}
if (surfaceParameter != null)
{
// Reorder so it won't be picked by other parameter that uses the same ID (eg. params from duplicated materials used as layers in other material)
surfaceParameters.Remove(surfaceParameter);
surfaceParameters.Add(surfaceParameter);
}
var attributes = surfaceParameter?.Meta.GetAttributes() ?? FlaxEngine.Utils.GetEmptyArray<Attribute>();
data[i] = new GraphParameterData(null, parameter.Name, parameter.IsPublic, ToType(parameter.ParameterType), attributes, parameter);
i++;

View File

@@ -192,15 +192,10 @@ void MaterialGenerator::prepareLayer(MaterialLayer* layer, bool allowVisiblePara
// For all not root layers (sub-layers) we won't to change theirs ID in order to prevent duplicated ID)
m.SrcId = param->Identifier;
if (isRooLayer)
m.DstId = param->Identifier;
if (!isRooLayer)
{
// Use the same ID (so we can edit it)
m.DstId = param->Identifier;
}
else
{
// Generate new ID
m.DstId = param->Identifier;
// Generate new ID (stable permutation based on the original ID)
m.DstId.A += _parameters.Count() * 17 + 13;
}
layer->ParamIdsMappings.Add(m);