diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 797bd5ee98..40555bae00 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -45,6 +45,9 @@ namespace AZ //! Return true if contained assets have not been loaded bool RequiresLoading() const; + //! Applies property overrides to material instance + bool ApplyProperties(); + //! Returns a string composed of the asset path. AZStd::string ToString() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index e70f0f5393..56ad6b8b52 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -132,6 +132,35 @@ namespace AZ !m_defaultMaterialAsset.IsLoading(); } + bool MaterialAssignment::ApplyProperties() + { + // if there is no instance or no properties there's nothing to apply + if (!m_materialInstance || m_propertyOverrides.empty()) + { + return true; + } + + if (m_materialInstance->CanCompile()) + { + for (const auto& propertyPair : m_propertyOverrides) + { + if (!propertyPair.second.empty()) + { + const auto& materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + if (!materialPropertyIndex.IsNull()) + { + m_materialInstance->SetPropertyValue( + materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); + } + } + } + + return m_materialInstance->Compile(); + } + + return false; + } + AZStd::string MaterialAssignment::ToString() const { AZStd::string assetPathString; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 69d2ef2460..cfb47d74f5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -147,56 +147,26 @@ namespace AZ void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZStd::unordered_set propertyOverrides; - AZStd::swap(m_queuedPropertyOverrides, propertyOverrides); + AZStd::unordered_set materialsWithDirtyProperties; + AZStd::swap(m_materialsWithDirtyProperties, materialsWithDirtyProperties); // Iterate through all MaterialAssignmentId's that have property overrides and attempt to apply them // if material instance is already compiling, delay application of property overrides until next frame - for (const auto& materialAssignmentId : propertyOverrides) + for (const auto& materialAssignmentId : materialsWithDirtyProperties) { const auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) + if (materialIt != m_configuration.m_materials.end()) { - //Skip materials that do not exist in the map - continue; - } - - auto materialInstance = materialIt->second.m_materialInstance; - if (!materialInstance) - { - //Skip materials with an invalid instances - continue; - } - - if (!materialInstance->CanCompile()) - { - //If a material cannot currently be compiled then it must be queued again - m_queuedPropertyOverrides.emplace(materialAssignmentId); - continue; - } - - const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides; - for (auto& propertyPair : propertyOverrides2) - { - if (propertyPair.second.empty()) + if (!materialIt->second.ApplyProperties()) { - continue; + // If a material cannot currently be compiled then it must be queued again + m_materialsWithDirtyProperties.emplace(materialAssignmentId); } - - const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first); - if (materialPropertyIndex.IsNull()) - { - continue; - } - - materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second)); } - - materialInstance->Compile(); } // Only disconnect from tick bus and send notification after all pending properties have been applied - if (m_queuedPropertyOverrides.empty()) + if (m_materialsWithDirtyProperties.empty()) { if (m_queuedMaterialUpdateNotification) { @@ -214,6 +184,18 @@ namespace AZ Data::AssetBus::MultiHandler::BusDisconnect(); bool anyQueued = false; + auto queueAsset = [&anyQueued, this](AZ::Data::Asset& materialAsset) -> bool + { + if (materialAsset.GetId().IsValid() && !this->Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) + { + anyQueued = true; + materialAsset.QueueLoad(); + this->Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId()); + return true; + } + return false; + }; + for (auto& materialPair : m_configuration.m_materials) { if (materialPair.second.m_materialInstancePreCreated) @@ -221,24 +203,16 @@ namespace AZ continue; } - if (materialPair.second.m_materialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_materialAsset.GetId())) + materialPair.second.m_defaultMaterialAsset = {}; + if (!queueAsset(materialPair.second.m_materialAsset)) { - anyQueued = true; - materialPair.second.m_materialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_materialAsset.GetId()); - continue; - } - - materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( - GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && - !Data::AssetBus::MultiHandler::BusIsConnectedId(materialPair.second.m_defaultMaterialAsset.GetId())) - { - anyQueued = true; - materialPair.second.m_defaultMaterialAsset.QueueLoad(); - Data::AssetBus::MultiHandler::BusConnect(materialPair.second.m_defaultMaterialAsset.GetId()); + // Only assign and load the default material if there was no material override and there are propoerties to apply + if (!materialPair.second.m_propertyOverrides.empty() || !materialPair.second.m_matModUvOverrides.empty()) + { + materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset( + GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo::Uuid()); + queueAsset(materialPair.second.m_defaultMaterialAsset); + } } } @@ -251,28 +225,23 @@ namespace AZ void MaterialComponentController::InitializeMaterialInstance(const Data::Asset& asset) { bool allReady = true; + auto updateAsset = [&](AZ::Data::Asset& materialAsset) + { + if (materialAsset.GetId() == asset.GetId()) + { + materialAsset = asset; + } + + if (materialAsset.GetId().IsValid() && !materialAsset.IsReady()) + { + allReady = false; + } + }; for (auto& materialPair : m_configuration.m_materials) { - if (materialPair.second.m_materialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_materialAsset = asset; - } - - if (materialPair.second.m_materialAsset.GetId().IsValid() && !materialPair.second.m_materialAsset.IsReady()) - { - allReady = false; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId() == asset.GetId()) - { - materialPair.second.m_defaultMaterialAsset = asset; - } - - if (materialPair.second.m_defaultMaterialAsset.GetId().IsValid() && !materialPair.second.m_defaultMaterialAsset.IsReady()) - { - allReady = false; - } + updateAsset(materialPair.second.m_materialAsset); + updateAsset(materialPair.second.m_defaultMaterialAsset); } if (allReady) @@ -463,12 +432,7 @@ namespace AZ AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const { auto materialIt = m_configuration.m_materials.find(materialAssignmentId); - if (materialIt == m_configuration.m_materials.end()) - { - return {}; - } - - return materialIt->second.m_materialAsset.GetId(); + return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_materialAsset.GetId() : AZ::Data::AssetId(); } void MaterialComponentController::ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) @@ -794,7 +758,7 @@ namespace AZ void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId) { - m_queuedPropertyOverrides.emplace(materialAssignmentId); + m_materialsWithDirtyProperties.emplace(materialAssignmentId); if (!TickBus::Handler::BusIsConnected()) { TickBus::Handler::BusConnect(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index b9bce4ce72..1594456a31 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -125,7 +125,7 @@ namespace AZ EntityId m_entityId; MaterialComponentConfig m_configuration; - AZStd::unordered_set m_queuedPropertyOverrides; + AZStd::unordered_set m_materialsWithDirtyProperties; bool m_queuedMaterialUpdateNotification = false; }; } // namespace Render