diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp index b757e4bd7e..85dc26089f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp @@ -16,7 +16,9 @@ namespace AZ AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0); JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load( - void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + void* outputValue, + [[maybe_unused]] const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; @@ -62,6 +64,7 @@ namespace AZ LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || + LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result)) { @@ -78,7 +81,10 @@ namespace AZ } JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store( - rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId, + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + [[maybe_unused]] const Uuid& valueTypeId, JsonSerializerContext& context) { namespace JSR = AZ::JsonSerializationResult; @@ -138,9 +144,9 @@ namespace AZ StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || + StoreAny>(propertyValue, outputPropertyValue, context, result) || StoreAny>(propertyValue, outputPropertyValue, context, result) || - StoreAny>( - propertyValue, outputPropertyValue, context, result)) + StoreAny>(propertyValue, outputPropertyValue, context, result)) { outputPropertyValueContainer.AddMember( rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue, @@ -164,7 +170,9 @@ namespace AZ template bool JsonMaterialAssignmentSerializer::LoadAny( - AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZStd::any& propertyValue, + const rapidjson::Value& inputPropertyValue, + AZ::JsonDeserializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type")) @@ -187,7 +195,9 @@ namespace AZ template bool JsonMaterialAssignmentSerializer::StoreAny( - const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + const AZStd::any& propertyValue, + rapidjson::Value& outputPropertyValue, + AZ::JsonSerializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (propertyValue.is()) @@ -199,7 +209,7 @@ namespace AZ result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context)); outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator()); - T value = AZStd::any_cast(propertyValue); + const T& value = AZStd::any_cast(propertyValue); result.Combine( ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid(), context)); return true; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h index e92d756639..069b4d4cdb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h @@ -25,21 +25,31 @@ namespace AZ AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load( - void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + void* outputValue, + const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) override; JsonSerializationResult::Result Store( - rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + const Uuid& valueTypeId, JsonSerializerContext& context) override; private: template bool LoadAny( - AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZStd::any& propertyValue, + const rapidjson::Value& inputPropertyValue, + AZ::JsonDeserializerContext& context, AZ::JsonSerializationResult::ResultCode& result); + template bool StoreAny( - const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + const AZStd::any& propertyValue, + rapidjson::Value& outputPropertyValue, + AZ::JsonSerializerContext& context, AZ::JsonSerializationResult::ResultCode& result); }; } // namespace Render diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 3ffd8efa6e..2ad4522094 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -33,11 +33,13 @@ namespace AtomToolsFramework { if (value.Is>()) { - const AZ::Data::Asset& imageAsset = value.GetValue>(); - return AZStd::any(AZ::Data::Asset( - imageAsset.GetId(), - azrtti_typeid(), - imageAsset.GetHint())); + const auto& imageAsset = value.GetValue>(); + return AZStd::any(AZ::Data::Asset(imageAsset.GetId(), azrtti_typeid(), imageAsset.GetHint())); + } + else if (value.Is>()) + { + const auto& image = value.GetValue>(); + return AZStd::any(AZ::Data::Asset(image->GetAssetId(), azrtti_typeid())); } return AZ::RPI::MaterialPropertyValue::ToAny(value); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 0ccdae28de..996a575c69 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -104,6 +104,7 @@ namespace AZ MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config) : m_configuration(config) { + ConvertAssetsForSerialization(); } void MaterialComponentController::Activate(EntityId entityId) @@ -135,6 +136,7 @@ namespace AZ void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config) { m_configuration = config; + ConvertAssetsForSerialization(); } const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const @@ -338,6 +340,7 @@ namespace AZ // before LoadMaterials() is called [LYN-2249] auto temp = m_configuration.m_materials; m_configuration.m_materials = materials; + ConvertAssetsForSerialization(); LoadMaterials(); } @@ -489,6 +492,7 @@ namespace AZ auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; + ConvertAssetsForSerialization(); if (materialAssignment.RequiresLoading()) { @@ -586,6 +590,7 @@ namespace AZ auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides = propertyOverrides; + ConvertAssetsForSerialization(); if (materialAssignment.RequiresLoading()) { @@ -667,5 +672,33 @@ namespace AZ TickBus::Handler::BusConnect(); } } + + void MaterialComponentController::ConvertAssetsForSerialization() + { + for (auto& materialAssignmentPair : m_configuration.m_materials) + { + MaterialAssignment& materialAssignment = materialAssignmentPair.second; + for (auto& propertyPair : materialAssignment.m_propertyOverrides) + { + auto& value = propertyPair.second; + if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value)->GetAssetId(); + } + } + } + } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 74b1cfda4d..d3eaa4433d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -99,6 +99,11 @@ namespace AZ //! Queue material instance recreation notifiucations until tick void QueueMaterialUpdateNotification(); + //! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property + //! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying + //! problem is resolved. + void ConvertAssetsForSerialization(); + EntityId m_entityId; MaterialComponentConfig m_configuration; AZStd::unordered_set m_materialsWithDirtyProperties;