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 089f4e8c62..58fb2e0f8a 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 @@ -1,21 +1,21 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once -#include -#include -#include #include +#include +#include #include +#include namespace AZ { @@ -31,39 +31,19 @@ namespace AZ MaterialAssignment() = default; - MaterialAssignment(const AZ::Data::AssetId& materialAssetId) - : m_materialInstance() - { - m_materialAsset.Create(materialAssetId); - } + MaterialAssignment(const AZ::Data::AssetId& materialAssetId); - MaterialAssignment(const Data::Asset& asset) - : m_materialAsset(asset) - , m_materialInstance() - { - } + MaterialAssignment(const Data::Asset& asset); - MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance) - : m_materialAsset(asset) - , m_materialInstance(instance) - { - } + MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance); - void RebuildInstance() - { - if (m_materialAsset.IsReady()) - { - m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); - AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); - } - } + //! Recreates the material instance from the asset if it has been loaded. + //! If amy property overrides have been specified then a unique instance will be created. + //! Otherwise an attempt will be made to find or create a shared instance. + void RebuildInstance(); - AZStd::string ToString() const - { - AZStd::string assetPathString; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAsset.GetId()); - return assetPathString; - } + //! Returns a string composed of the asset path. + AZStd::string ToString() const; Data::Asset m_materialAsset; Data::Instance m_materialInstance; @@ -77,64 +57,15 @@ namespace AZ static const MaterialAssignmentMap DefaultMaterialAssignmentMap; //! Utility function for retrieving a material entry from a MaterialAssignmentMap - AZ_INLINE const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) - { - const auto& materialItr = materials.find(id); - return materialItr != materials.end() ? materialItr->second : DefaultMaterialAssignment; - } + const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id); - //! Utility function for retrieving a material entry from a MaterialAssignmentMap, falling back to defaults for a particular asset or the entire model - AZ_INLINE const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) - { - const MaterialAssignment& lodAssignment = GetMaterialAssignmentFromMap(materials, id); - if (lodAssignment.m_materialInstance.get()) - { - return lodAssignment; - } - - const MaterialAssignment& assetAssignment = GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromAssetOnly(id.m_materialAssetId)); - if (assetAssignment.m_materialInstance.get()) - { - return assetAssignment; - } - - const MaterialAssignment& defaultAssignment = GetMaterialAssignmentFromMap(materials, DefaultMaterialAssignmentId); - if (defaultAssignment.m_materialInstance.get()) - { - return defaultAssignment; - } - - return DefaultMaterialAssignment; - } + //! Utility function for retrieving a material entry from a MaterialAssignmentMap, falling back to defaults for a particular asset + //! or the entire model + const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback( + const MaterialAssignmentMap& materials, const MaterialAssignmentId& id); //! Utility function for generating a set of available material assignments in a model - AZ_INLINE MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model) - { - MaterialAssignmentMap materials; - materials[DefaultMaterialAssignmentId] = MaterialAssignment(); - - if (model) - { - size_t lodIndex = 0; - for (const Data::Instance& lod : model->GetLods()) - { - for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) - { - if (mesh.m_material) - { - const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromAssetOnly(mesh.m_material->GetAssetId()); - materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); - - const MaterialAssignmentId specificId = MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); - materials[specificId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); - } - } - ++lodIndex; - } - } - - return materials; - } + MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model); } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h index 267e65743a..80de6d8041 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h @@ -1,20 +1,20 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once +#include #include #include -#include #include #include #include @@ -26,6 +26,9 @@ namespace AZ { using MaterialAssignmentLodIndex = AZ::u64; + //! MaterialAssignmentId is used to address available and overridable material slots on a model. + //! The LOD and one of the model's original material asset IDs are used as coordinates that identify + //! a specific material slot or a set of slots matching either. struct MaterialAssignmentId final { AZ_RTTI(AZ::Render::MaterialAssignmentId, "{EB603581-4654-4C17-B6DE-AE61E79EDA97}"); @@ -34,69 +37,37 @@ namespace AZ MaterialAssignmentId() = default; - MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId) - : m_lodIndex(lodIndex) - , m_materialAssetId(materialAssetId) - { - } + MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId); - static MaterialAssignmentId CreateDefault() - { - return MaterialAssignmentId(NonLodIndex, AZ::Data::AssetId()); - } + //! Create an ID that maps to all material slots, regardless of asset ID or LOD, effectively applying to an entire model. + static MaterialAssignmentId CreateDefault(); - static MaterialAssignmentId CreateFromAssetOnly(AZ::Data::AssetId materialAssetId) - { - return MaterialAssignmentId(NonLodIndex, materialAssetId); - } + //! Create an ID that maps to all material slots with a corresponding asset ID, regardless of LOD. + static MaterialAssignmentId CreateFromAssetOnly(AZ::Data::AssetId materialAssetId); - static MaterialAssignmentId CreateFromLodAndAsset(MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId) - { - return MaterialAssignmentId(lodIndex, materialAssetId); - } + //! Create an ID that maps to a specific material slot with a corresponding asset ID and LOD. + static MaterialAssignmentId CreateFromLodAndAsset(MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId); - bool IsDefault() const - { - return m_lodIndex == NonLodIndex && !m_materialAssetId.IsValid(); - } + //! Returns true if the asset ID and LOD are invalid + bool IsDefault() const; - bool IsAssetOnly() const - { - return m_lodIndex == NonLodIndex && m_materialAssetId.IsValid(); - } + //! Returns true if the asset ID is valid and LOD is invalid + bool IsAssetOnly() const; - bool IsLodAndAsset() const - { - return m_lodIndex != NonLodIndex && m_materialAssetId.IsValid(); - } + //! Returns true if the asset ID and LOD are both valid + bool IsLodAndAsset() const; + //! Creates a string composed of the asset path and LOD + AZStd::string ToString() const; - AZStd::string ToString() const - { - AZStd::string assetPathString; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAssetId); - AZ::StringFunc::Path::StripPath(assetPathString); - AZ::StringFunc::Path::StripExtension(assetPathString); - return AZStd::string::format("%s:%llu", assetPathString.c_str(), m_lodIndex); - } + //! Creates a hash composed of the asset ID sub ID and LOD + size_t GetHash() const; - size_t GetHash() const - { - size_t seed = 0; - AZStd::hash_combine(seed, m_lodIndex); - AZStd::hash_combine(seed, m_materialAssetId); - return seed; - } + //! Returns true if both asset ID sub IDs and LODs match + bool operator==(const MaterialAssignmentId& rhs) const; - bool operator==(const MaterialAssignmentId& rhs) const - { - return m_lodIndex == rhs.m_lodIndex && m_materialAssetId == rhs.m_materialAssetId; - } - - bool operator!=(const MaterialAssignmentId& rhs) const - { - return m_lodIndex != rhs.m_lodIndex || m_materialAssetId != rhs.m_materialAssetId; - } + //! Returns true if both asset ID sub IDs and LODs do not match + bool operator!=(const MaterialAssignmentId& rhs) const; static constexpr MaterialAssignmentLodIndex NonLodIndex = -1; MaterialAssignmentLodIndex m_lodIndex = NonLodIndex; @@ -116,4 +87,4 @@ namespace AZStd return id.GetHash(); } }; -} //namespace AZStd +} // namespace AZStd diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index f817e8324b..ffb5469aef 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include namespace AZ { @@ -67,5 +67,101 @@ namespace AZ } } + + MaterialAssignment::MaterialAssignment(const AZ::Data::AssetId& materialAssetId) + : m_materialInstance() + { + m_materialAsset.Create(materialAssetId); + } + + MaterialAssignment::MaterialAssignment(const Data::Asset& asset) + : m_materialAsset(asset) + , m_materialInstance() + { + } + + MaterialAssignment::MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance) + : m_materialAsset(asset) + , m_materialInstance(instance) + { + } + + void MaterialAssignment::RebuildInstance() + { + if (m_materialAsset.IsReady()) + { + m_materialInstance = + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); + } + } + + AZStd::string MaterialAssignment::ToString() const + { + AZStd::string assetPathString; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAsset.GetId()); + return assetPathString; + } + + const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) + { + const auto& materialItr = materials.find(id); + return materialItr != materials.end() ? materialItr->second : DefaultMaterialAssignment; + } + + const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback( + const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) + { + const MaterialAssignment& lodAssignment = GetMaterialAssignmentFromMap(materials, id); + if (lodAssignment.m_materialInstance.get()) + { + return lodAssignment; + } + + const MaterialAssignment& assetAssignment = + GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromAssetOnly(id.m_materialAssetId)); + if (assetAssignment.m_materialInstance.get()) + { + return assetAssignment; + } + + const MaterialAssignment& defaultAssignment = GetMaterialAssignmentFromMap(materials, DefaultMaterialAssignmentId); + if (defaultAssignment.m_materialInstance.get()) + { + return defaultAssignment; + } + + return DefaultMaterialAssignment; + } + + MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model) + { + MaterialAssignmentMap materials; + materials[DefaultMaterialAssignmentId] = MaterialAssignment(); + + if (model) + { + size_t lodIndex = 0; + for (const Data::Instance& lod : model->GetLods()) + { + for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) + { + if (mesh.m_material) + { + const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromAssetOnly(mesh.m_material->GetAssetId()); + materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); + + const MaterialAssignmentId specificId = + MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); + materials[specificId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); + } + } + ++lodIndex; + } + } + + return materials; + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp index 4813136d2e..59de229445 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include namespace AZ { @@ -47,5 +47,70 @@ namespace AZ ; } } + + MaterialAssignmentId::MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId) + : m_lodIndex(lodIndex) + , m_materialAssetId(materialAssetId) + { + } + + MaterialAssignmentId MaterialAssignmentId::CreateDefault() + { + return MaterialAssignmentId(NonLodIndex, AZ::Data::AssetId()); + } + + MaterialAssignmentId MaterialAssignmentId::CreateFromAssetOnly(AZ::Data::AssetId materialAssetId) + { + return MaterialAssignmentId(NonLodIndex, materialAssetId); + } + + MaterialAssignmentId MaterialAssignmentId::CreateFromLodAndAsset( + MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId) + { + return MaterialAssignmentId(lodIndex, materialAssetId); + } + + bool MaterialAssignmentId::IsDefault() const + { + return m_lodIndex == NonLodIndex && !m_materialAssetId.IsValid(); + } + + bool MaterialAssignmentId::IsAssetOnly() const + { + return m_lodIndex == NonLodIndex && m_materialAssetId.IsValid(); + } + + bool MaterialAssignmentId::IsLodAndAsset() const + { + return m_lodIndex != NonLodIndex && m_materialAssetId.IsValid(); + } + + AZStd::string MaterialAssignmentId::ToString() const + { + AZStd::string assetPathString; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAssetId); + AZ::StringFunc::Path::StripPath(assetPathString); + AZ::StringFunc::Path::StripExtension(assetPathString); + return AZStd::string::format("%s:%llu", assetPathString.c_str(), m_lodIndex); + } + + size_t MaterialAssignmentId::GetHash() const + { + size_t seed = 0; + AZStd::hash_combine(seed, m_lodIndex); + AZStd::hash_combine(seed, m_materialAssetId.m_subId); + return seed; + } + + bool MaterialAssignmentId::operator==(const MaterialAssignmentId& rhs) const + { + return m_lodIndex == rhs.m_lodIndex && m_materialAssetId.m_subId == rhs.m_materialAssetId.m_subId; + } + + bool MaterialAssignmentId::operator!=(const MaterialAssignmentId& rhs) const + { + return !(*this == rhs); + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 47000d8a5c..8926b0c19f 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -27,8 +27,6 @@ set(FILES Include/Atom/Feature/ImGui/SystemBus.h Include/Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h Include/Atom/Feature/LookupTable/LookupTableAsset.h - Include/Atom/Feature/Material/MaterialAssignment.h - Include/Atom/Feature/Material/MaterialAssignmentId.h Include/Atom/Feature/Mesh/MeshFeatureProcessor.h Include/Atom/Feature/PostProcessing/PostProcessingConstants.h Include/Atom/Feature/PostProcessing/SMAAFeatureProcessorInterface.h @@ -155,8 +153,6 @@ set(FILES Source/LookupTable/LookupTableAsset.cpp Source/Material/ConvertEmissiveUnitFunctor.cpp Source/Material/ConvertEmissiveUnitFunctor.h - Source/Material/MaterialAssignment.cpp - Source/Material/MaterialAssignmentId.cpp Source/Material/ShaderEnableFunctor.cpp Source/Material/ShaderEnableFunctor.h Source/Material/SubsurfaceTransmissionParameterFunctor.cpp diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake index d33e861c02..553f307409 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake @@ -10,8 +10,12 @@ # set(FILES + Include/Atom/Feature/Material/MaterialAssignment.h + Include/Atom/Feature/Material/MaterialAssignmentId.h Include/Atom/Feature/Utils/LightingPreset.h Include/Atom/Feature/Utils/ModelPreset.h + Source/Material/MaterialAssignment.cpp + Source/Material/MaterialAssignmentId.cpp Source/Utils/LightingPreset.cpp Source/Utils/ModelPreset.cpp ) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index dc969d61d3..6492f4f13a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -25,6 +25,7 @@ ly_add_target( Gem::Atom_Utils.Static Gem::Atom_Feature_Common Gem::Atom_Feature_Common.Public + Gem::Atom_Feature_Common.Static Gem::Atom_RPI.Public Gem::Atom_RHI.Reflect Gem::AtomLyIntegration_CommonFeatures.Public