Files
o3de/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp
T
guthadam 931a127b7b ATOM-15223 updating material assignment ID to be portable to other models
The bug was reported that copy and paste did not work with the material component.
Copy and paste to take the worked fine.
All of the material assignments/overrides get mapped using the LOD and asset ID of materials provided with the model.
The asset IDs of materials exported by atom builders, using the scene API, are the combination of the same UUID as the model asset ID and the unique sub ID that is now hashed from the material name provided by the DCC tool.
If we map material assignments using the entire asset ID that was generated in the model builder then the mapping will only work with that specific model.
This change updates the material assignment ID equality operators and hash function to only use the sub ID portion of the asset ID.
As long as the sub IDs are generated consistently the material assignment mappings will be portable to models with the same material names.

Also moved material assignment structures to atom common features static library so this was to be moved to cpp files
2021-05-12 13:47:47 -05:00

168 lines
7.6 KiB
C++

/*
* 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.
*
*/
#include <Atom/Feature/Material/MaterialAssignment.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace Render
{
void MaterialAssignment::Reflect(ReflectContext* context)
{
MaterialAssignmentId::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->RegisterGenericType<MaterialAssignmentMap>();
serializeContext->RegisterGenericType<MaterialPropertyOverrideMap>();
serializeContext->Class<MaterialAssignment>()
->Version(1)
->Field("MaterialAsset", &MaterialAssignment::m_materialAsset)
->Field("PropertyOverrides", &MaterialAssignment::m_propertyOverrides)
;
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<MaterialAssignment>("MaterialAssignment")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render")
->Constructor()
->Constructor<const MaterialAssignment&>()
->Constructor<const AZ::Data::AssetId&>()
->Constructor<const Data::Asset<RPI::MaterialAsset>&>()
->Constructor<const Data::Asset<RPI::MaterialAsset>&, const Data::Instance<RPI::Material>&>()
->Method("ToString", &MaterialAssignment::ToString)
->Property("materialAsset", BehaviorValueProperty(&MaterialAssignment::m_materialAsset))
->Property("propertyOverrides", BehaviorValueProperty(&MaterialAssignment::m_propertyOverrides))
;
behaviorContext->ConstantProperty("DefaultMaterialAssignment", BehaviorConstant(DefaultMaterialAssignment))
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render");
behaviorContext->ConstantProperty("DefaultMaterialAssignmentId", BehaviorConstant(DefaultMaterialAssignmentId))
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render");
behaviorContext->ConstantProperty("DefaultMaterialAssignmentMap", BehaviorConstant(DefaultMaterialAssignmentMap))
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render");
}
}
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