Changed .material serialization to avoid loading the .materialtype file, since the .material builder doesn't declare a source dependency on the .materialtype. Otherwise there can be ambiguous edge cases where changes to the .materialtype might or might not impact the baked MaterialAsset. Note that another option would have been to add a the appropriate source dependency, but that would hurt iteration time as any change to the .materialtype file would cause every .material file and .fbx to rebuild.

These changes have the added benefit of simplifying some of the serialization code. MaterialSourceDataSerializer is no longer needed, as its main purpose was to pass the MaterialTypeSourceData down to the MaterialPropertyValueSerializer.

Before, the JSON serialization system gave a lot of data flexibility because it did best-effort conversions, like allowing a float to be loaded as an int for example. But now the material serialization code doesn't know target data type, so it has to assume the data type based on what's in the .material file, and then the MaterialAsset will convert the data to the appropriate type later when Finalize() is called.

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
santorac
2022-01-14 12:57:52 -08:00
parent 3bbb8d78cd
commit a896ff11bc
12 changed files with 450 additions and 481 deletions
@@ -109,6 +109,77 @@ namespace AZ
return m_wasPreFinalized;
}
template<typename T>
MaterialPropertyValue CastNumericMaterialPropertyValue(const MaterialPropertyValue& value)
{
TypeId typeId = value.GetTypeId();
if (typeId == azrtti_typeid<bool>())
{
return aznumeric_cast<T>(value.GetValue<bool>());
}
else if (typeId == azrtti_typeid<int32_t>())
{
return aznumeric_cast<T>(value.GetValue<int32_t>());
}
else if (typeId == azrtti_typeid<uint32_t>())
{
return aznumeric_cast<T>(value.GetValue<uint32_t>());
}
else if (typeId == azrtti_typeid<float>())
{
return aznumeric_cast<T>(value.GetValue<float>());
}
else
{
return value;
}
}
template<typename VectorT>
MaterialPropertyValue CastVectorMaterialPropertyValue(const MaterialPropertyValue& value)
{
float values[4] = {};
TypeId typeId = value.GetTypeId();
if (typeId == azrtti_typeid<Vector2>())
{
value.GetValue<Vector2>().StoreToFloat2(values);
}
else if (typeId == azrtti_typeid<Vector3>())
{
value.GetValue<Vector3>().StoreToFloat3(values);
}
else if (typeId == azrtti_typeid<Vector4>())
{
value.GetValue<Vector4>().StoreToFloat4(values);
}
else
{
return value;
}
typeId = azrtti_typeid<VectorT>();
if (typeId == azrtti_typeid<Vector2>())
{
return Vector2::CreateFromFloat2(values);
}
else if (typeId == azrtti_typeid<Vector3>())
{
return Vector3::CreateFromFloat3(values);
}
else if (typeId == azrtti_typeid<Vector4>())
{
return Vector4::CreateFromFloat4(values);
}
else
{
return value;
}
}
void MaterialAsset::Finalize(AZStd::function<void(const char*)> reportWarning, AZStd::function<void(const char*)> reportError)
{
if (m_wasPreFinalized)
@@ -180,9 +251,66 @@ namespace AZ
}
else
{
if (ValidateMaterialPropertyDataType(value.GetTypeId(), name, propertyDescriptor, reportError))
// The material asset could be finalized sometime after the original JSON is loaded, and the material type might not have been available
// at that time, so the data type would not be known for each property. So each raw property's type could be based on what appeared in the JSON
// and this is the first opportunity we have to resolve that value with the actual type. For example, a float property could have been specified in
// the JSON as 7 instead of 7.0, which is valid. Similarly, a Color and a Vector3 can both be specified as "[0.0,0.0,0.0]" in the JSON file.
MaterialPropertyValue finalValue = value;
switch (propertyDescriptor->GetDataType())
{
finalizedPropertyValues[propertyIndex.GetIndex()] = value;
case MaterialPropertyDataType::Bool:
finalValue = CastNumericMaterialPropertyValue<bool>(value);
break;
case MaterialPropertyDataType::Int:
finalValue = CastNumericMaterialPropertyValue<int32_t>(value);
break;
case MaterialPropertyDataType::UInt:
finalValue = CastNumericMaterialPropertyValue<uint32_t>(value);
break;
case MaterialPropertyDataType::Float:
finalValue = CastNumericMaterialPropertyValue<float>(value);
break;
case MaterialPropertyDataType::Color:
if (value.GetTypeId() == azrtti_typeid<Vector3>())
{
finalValue = Color::CreateFromVector3(value.GetValue<Vector3>());
}
else if (value.GetTypeId() == azrtti_typeid<Vector4>())
{
Vector4 vector4 = value.GetValue<Vector4>();
finalValue = Color::CreateFromVector3AndFloat(vector4.GetAsVector3(), vector4.GetW());
}
break;
case MaterialPropertyDataType::Vector2:
finalValue = CastVectorMaterialPropertyValue<Vector2>(value);
break;
case MaterialPropertyDataType::Vector3:
if (value.GetTypeId() == azrtti_typeid<Color>())
{
finalValue = value.GetValue<Color>().GetAsVector3();
}
else
{
finalValue = CastVectorMaterialPropertyValue<Vector3>(value);
}
break;
case MaterialPropertyDataType::Vector4:
if (value.GetTypeId() == azrtti_typeid<Color>())
{
finalValue = value.GetValue<Color>().GetAsVector4();
}
else
{
finalValue = CastVectorMaterialPropertyValue<Vector4>(value);
}
break;
}
if (ValidateMaterialPropertyDataType(finalValue.GetTypeId(), name, propertyDescriptor, reportError))
{
finalizedPropertyValues[propertyIndex.GetIndex()] = finalValue;
}
}
}