Merge pull request #726 from aws-lumberyard-dev/Atom/guthadam/ATOM-15223

ATOM-15223 updating material assignment ID to be portable to other models
This commit is contained in:
Guthrie Adams
2021-05-13 17:21:07 -05:00
committed by GitHub
7 changed files with 232 additions and 168 deletions
@@ -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 <Atom/RPI.Public/Material/Material.h>
#include <AzCore/std/containers/unordered_map.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <Atom/Feature/Material/MaterialAssignmentId.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/std/containers/unordered_map.h>
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<RPI::MaterialAsset>& asset)
: m_materialAsset(asset)
, m_materialInstance()
{
}
MaterialAssignment(const Data::Asset<RPI::MaterialAsset>& asset);
MaterialAssignment(const Data::Asset<RPI::MaterialAsset>& asset, const Data::Instance<RPI::Material>& instance)
: m_materialAsset(asset)
, m_materialInstance(instance)
{
}
MaterialAssignment(const Data::Asset<RPI::MaterialAsset>& asset, const Data::Instance<RPI::Material>& 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<RPI::MaterialAsset> m_materialAsset;
Data::Instance<RPI::Material> 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<AZ::RPI::Model> model)
{
MaterialAssignmentMap materials;
materials[DefaultMaterialAssignmentId] = MaterialAssignment();
if (model)
{
size_t lodIndex = 0;
for (const Data::Instance<AZ::RPI::ModelLod>& 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<AZ::RPI::Model> model);
} // namespace Render
} // namespace AZ
@@ -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 <AzCore/Asset/AssetCommon.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/ReflectContext.h>
@@ -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
@@ -11,8 +11,8 @@
*/
#include <Atom/Feature/Material/MaterialAssignment.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
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<RPI::MaterialAsset>& asset)
: m_materialAsset(asset)
, m_materialInstance()
{
}
MaterialAssignment::MaterialAssignment(const Data::Asset<RPI::MaterialAsset>& asset, const Data::Instance<RPI::Material>& 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<AZ::RPI::Model> model)
{
MaterialAssignmentMap materials;
materials[DefaultMaterialAssignmentId] = MaterialAssignment();
if (model)
{
size_t lodIndex = 0;
for (const Data::Instance<AZ::RPI::ModelLod>& 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
@@ -11,8 +11,8 @@
*/
#include <Atom/Feature/Material/MaterialAssignmentId.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
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
@@ -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
@@ -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
)
@@ -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