Merge pull request #5482 from aws-lumberyard-dev/Atom/antonmic/skinMeshSrgFix

Fixed issue where skin material wouldn't render if applied to a model with several submeshes and those submeshes had different material types applied to them.
This commit is contained in:
antonmic
2021-11-10 14:28:51 -08:00
committed by GitHub
6 changed files with 158 additions and 146 deletions
@@ -30,7 +30,7 @@ namespace AZ
class TransformServiceFeatureProcessor;
class RayTracingFeatureProcessor;
class MeshDataInstance
class ModelDataInstance
{
friend class MeshFeatureProcessor;
friend class MeshLoader;
@@ -47,7 +47,7 @@ namespace AZ
public:
using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent;
MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, MeshDataInstance* parent);
MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, ModelDataInstance* parent);
~MeshLoader();
ModelChangedEvent& GetModelChangedEvent();
@@ -68,7 +68,7 @@ namespace AZ
} };
MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent;
Data::Asset<RPI::ModelAsset> m_modelAsset;
MeshDataInstance* m_parent = nullptr;
ModelDataInstance* m_parent = nullptr;
};
void DeInit();
@@ -99,7 +99,8 @@ namespace AZ
//! A reference to the original model asset in case it got cloned before creating the model instance.
Data::Asset<RPI::ModelAsset> m_originalModelAsset;
Data::Instance<RPI::ShaderResourceGroup> m_shaderResourceGroup;
//! List of object SRGs used by meshes in this model
AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>> m_objectSrgList;
AZStd::unique_ptr<MeshLoader> m_meshLoader;
RPI::Scene* m_scene = nullptr;
RHI::DrawItemSortKey m_sortKey;
@@ -152,7 +153,7 @@ namespace AZ
Data::Instance<RPI::Model> GetModel(const MeshHandle& meshHandle) const override;
Data::Asset<RPI::ModelAsset> GetModelAsset(const MeshHandle& meshHandle) const override;
Data::Instance<RPI::ShaderResourceGroup> GetObjectSrg(const MeshHandle& meshHandle) const override;
const AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>>& GetObjectSrgs(const MeshHandle& meshHandle) const override;
void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material) override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override;
@@ -195,7 +196,7 @@ namespace AZ
void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override;
AZStd::concurrency_checker m_meshDataChecker;
StableDynamicArray<MeshDataInstance> m_meshData;
StableDynamicArray<ModelDataInstance> m_modelData;
TransformServiceFeatureProcessor* m_transformService;
RayTracingFeatureProcessor* m_rayTracingFeatureProcessor = nullptr;
AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate;
@@ -20,7 +20,7 @@ namespace AZ
{
namespace Render
{
class MeshDataInstance;
class ModelDataInstance;
//! Settings to apply to a mesh handle when acquiring it for the first time
struct MeshHandleDescriptor
@@ -40,7 +40,7 @@ namespace AZ
public:
AZ_RTTI(AZ::Render::MeshFeatureProcessorInterface, "{975D7F0C-2E7E-4819-94D0-D3C4E2024721}", FeatureProcessor);
using MeshHandle = StableDynamicArrayHandle<MeshDataInstance>;
using MeshHandle = StableDynamicArrayHandle<ModelDataInstance>;
using ModelChangedEvent = Event<const Data::Instance<RPI::Model>>;
//! Acquires a model with an optional collection of material assignments.
@@ -61,12 +61,15 @@ namespace AZ
virtual Data::Instance<RPI::Model> GetModel(const MeshHandle& meshHandle) const = 0;
//! Gets the underlying RPI::ModelAsset for a meshHandle.
virtual Data::Asset<RPI::ModelAsset> GetModelAsset(const MeshHandle& meshHandle) const = 0;
//! Gets the ObjectSrg for a meshHandle.
//! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile,
//! instead of compiling the srg directly. This way, if the srg has already been queued for compile,
//! it will not be queued twice in the same frame. The ObjectSrg should not be updated during
//! Gets the ObjectSrgs for a meshHandle.
//! Updating the ObjectSrgs should be followed by a call to QueueObjectSrgForCompile,
//! instead of compiling the srgs directly. This way, if the srgs have already been queued for compile,
//! they will not be queued twice in the same frame. The ObjectSrgs should not be updated during
//! Simulate, or it will create a race between updating the data and the call to Compile
virtual Data::Instance<RPI::ShaderResourceGroup> GetObjectSrg(const MeshHandle& meshHandle) const = 0;
//! Cases where there may be multiple ObjectSrgs: if a model has multiple submeshes and those submeshes use different
//! materials with different object SRGs.
virtual const AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0;
//! Queues the object srg for compile.
virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0;
//! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId.
@@ -19,7 +19,7 @@ namespace UnitTest
MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&));
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr<AZ::RPI::Model>(const MeshHandle&));
MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset<AZ::RPI::ModelAsset>(const MeshHandle&));
MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr<AZ::RPI::ShaderResourceGroup>(const MeshHandle&));
MOCK_CONST_METHOD1(GetObjectSrgs, const AZStd::vector<AZStd::intrusive_ptr<AZ::RPI::ShaderResourceGroup>>&(const MeshHandle&));
MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
@@ -67,7 +67,7 @@ namespace AZ
m_handleGlobalShaderOptionUpdate.Disconnect();
DisableSceneNotification();
AZ_Warning("MeshFeatureProcessor", m_meshData.size() == 0,
AZ_Warning("MeshFeatureProcessor", m_modelData.size() == 0,
"Deactivaing the MeshFeatureProcessor, but there are still outstanding mesh handles.\n"
);
m_transformService = nullptr;
@@ -81,7 +81,7 @@ namespace AZ
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
const auto iteratorRanges = m_meshData.GetParallelRanges();
const auto iteratorRanges = m_modelData.GetParallelRanges();
AZ::JobCompletion jobCompletion;
for (const auto& iteratorRange : iteratorRanges)
{
@@ -125,11 +125,11 @@ namespace AZ
m_forceRebuildDrawPackets = false;
// CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread
for (MeshDataInstance& meshDataInstance : m_meshData)
for (ModelDataInstance& modelDataInstance : m_modelData)
{
if (meshDataInstance.m_model && meshDataInstance.m_cullBoundsNeedsUpdate)
if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate)
{
meshDataInstance.UpdateCullBounds(m_transformService);
modelDataInstance.UpdateCullBounds(m_transformService);
}
}
}
@@ -151,14 +151,14 @@ namespace AZ
AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh");
// don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion
MeshHandle meshDataHandle = m_meshData.emplace();
MeshHandle meshDataHandle = m_modelData.emplace();
meshDataHandle->m_descriptor = descriptor;
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset;
meshDataHandle->m_meshLoader = AZStd::make_unique<MeshDataInstance::MeshLoader>(descriptor.m_modelAsset, &*meshDataHandle);
meshDataHandle->m_meshLoader = AZStd::make_unique<ModelDataInstance::MeshLoader>(descriptor.m_modelAsset, &*meshDataHandle);
return meshDataHandle;
}
@@ -183,7 +183,7 @@ namespace AZ
m_transformService->ReleaseObjectId(meshHandle->m_objectId);
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
m_meshData.erase(meshHandle);
m_modelData.erase(meshHandle);
return true;
}
@@ -215,9 +215,10 @@ namespace AZ
return {};
}
Data::Instance<RPI::ShaderResourceGroup> MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const
const AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const
{
return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr;
static AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>> staticEmptyList;
return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList;
}
void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
@@ -274,9 +275,9 @@ namespace AZ
{
if (meshHandle.IsValid())
{
MeshDataInstance& meshData = *meshHandle;
meshData.m_cullBoundsNeedsUpdate = true;
meshData.m_objectSrgNeedsUpdate = true;
ModelDataInstance& modelData = *meshHandle;
modelData.m_cullBoundsNeedsUpdate = true;
modelData.m_objectSrgNeedsUpdate = true;
m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale);
@@ -292,10 +293,10 @@ namespace AZ
{
if (meshHandle.IsValid())
{
MeshDataInstance& meshData = *meshHandle;
meshData.m_aabb = localAabb;
meshData.m_cullBoundsNeedsUpdate = true;
meshData.m_objectSrgNeedsUpdate = true;
ModelDataInstance& modelData = *meshHandle;
modelData.m_aabb = localAabb;
modelData.m_cullBoundsNeedsUpdate = true;
modelData.m_objectSrgNeedsUpdate = true;
}
};
@@ -465,7 +466,7 @@ namespace AZ
void MeshFeatureProcessor::UpdateMeshReflectionProbes()
{
// we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option
for (auto& meshInstance : m_meshData)
for (auto& meshInstance : m_modelData)
{
if (meshInstance.m_descriptor.m_useForwardPassIblSpecular)
{
@@ -474,14 +475,14 @@ namespace AZ
}
}
// MeshDataInstance::MeshLoader...
MeshDataInstance::MeshLoader::MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, MeshDataInstance* parent)
// ModelDataInstance::MeshLoader...
ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, ModelDataInstance* parent)
: m_modelAsset(modelAsset)
, m_parent(parent)
{
if (!m_modelAsset.GetId().IsValid())
{
AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
AZ_Error("ModelDataInstance::MeshLoader", false, "Invalid model asset Id.");
return;
}
@@ -494,19 +495,19 @@ namespace AZ
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
MeshDataInstance::MeshLoader::~MeshLoader()
ModelDataInstance::MeshLoader::~MeshLoader()
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
Data::AssetBus::Handler::BusDisconnect();
}
MeshFeatureProcessorInterface::ModelChangedEvent& MeshDataInstance::MeshLoader::GetModelChangedEvent()
MeshFeatureProcessorInterface::ModelChangedEvent& ModelDataInstance::MeshLoader::GetModelChangedEvent()
{
return m_modelChangedEvent;
}
//! AssetBus::Handler overrides...
void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
Data::Asset<RPI::ModelAsset> modelAsset = asset;
@@ -527,7 +528,7 @@ namespace AZ
}
else
{
AZ_Error("MeshDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
AZ_Error("ModelDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
model = RPI::Model::FindOrCreate(modelAsset);
}
}
@@ -547,29 +548,29 @@ namespace AZ
{
//when running with null renderer, the RPI::Model::FindOrCreate(...) is expected to return nullptr, so suppress this error.
AZ_Error(
"MeshDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
"ModelDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
asset.GetHint().c_str());
}
}
void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset<Data::AssetData> asset)
void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset<Data::AssetData> asset)
{
OnAssetReady(asset);
}
void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset<Data::AssetData> asset)
void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset<Data::AssetData> asset)
{
// Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization
AZ_Error(
"MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
"ModelDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
m_modelAsset.GetHint().c_str());
AzFramework::AssetSystemRequestBus::Broadcast(
&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid);
}
void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
void ModelDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -584,7 +585,7 @@ namespace AZ
}
}
void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
void ModelDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -599,9 +600,9 @@ namespace AZ
}
}
// MeshDataInstance...
// ModelDataInstance...
void MeshDataInstance::DeInit()
void ModelDataInstance::DeInit()
{
m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
@@ -609,11 +610,11 @@ namespace AZ
m_drawPacketListsByLod.clear();
m_materialAssignments.clear();
m_shaderResourceGroup = {};
m_objectSrgList = {};
m_model = {};
}
void MeshDataInstance::Init(Data::Instance<RPI::Model> model)
void ModelDataInstance::Init(Data::Instance<RPI::Model> model)
{
m_model = model;
const size_t modelLodCount = m_model->GetLodCount();
@@ -623,11 +624,11 @@ namespace AZ
BuildDrawPacketList(modelLodIndex);
}
if (m_shaderResourceGroup)
for(auto& objectSrg : m_objectSrgList)
{
// Set object Id once since it never changes
RHI::ShaderInputNameIndex objectIdIndex = "m_objectId";
m_shaderResourceGroup->SetConstant(objectIdIndex, m_objectId.GetIndex());
objectSrg->SetConstant(objectIdIndex, m_objectId.GetIndex());
objectIdIndex.AssertValid();
}
@@ -643,12 +644,12 @@ namespace AZ
m_objectSrgNeedsUpdate = true;
}
void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
void ModelDataInstance::BuildDrawPacketList(size_t modelLodIndex)
{
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
const size_t meshCount = modelLod.GetMeshes().size();
MeshDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
ModelDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
drawPacketListOut.clear();
drawPacketListOut.reserve(meshCount);
@@ -682,27 +683,32 @@ namespace AZ
continue;
}
if (m_shaderResourceGroup && m_shaderResourceGroup->GetLayout()->GetHash() != objectSrgLayout->GetHash())
Data::Instance<RPI::ShaderResourceGroup> meshObjectSrg;
// See if the object SRG for this mesh is already in our list of object SRGs
for (auto& objectSrgIter : m_objectSrgList)
{
AZ_Warning("MeshFeatureProcessor", false, "All materials on a model must use the same per-object ShaderResourceGroup. Skipping.");
continue;
if (objectSrgIter->GetLayout()->GetHash() == objectSrgLayout->GetHash())
{
meshObjectSrg = objectSrgIter;
}
}
// The first time we find the per-surface SRG asset we create an instance and store it
// in shaderResourceGroupInOut. All of the Model's draw packets will use this same instance.
if (!m_shaderResourceGroup)
// If the object SRG for this mesh was not already in the list, create it and add it to the list
if (!meshObjectSrg)
{
auto& shaderAsset = material->GetAsset()->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg();
m_shaderResourceGroup = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
if (!m_shaderResourceGroup)
meshObjectSrg = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
if (!meshObjectSrg)
{
AZ_Warning("MeshFeatureProcessor", false, "Failed to create a new shader resource group, skipping.");
continue;
}
m_objectSrgList.push_back(meshObjectSrg);
}
// setup the mesh draw packet
RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides);
RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, materialAssignment.m_matModUvOverrides);
// set the shader option to select forward pass IBL specular if necessary
if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular }))
@@ -726,7 +732,7 @@ namespace AZ
}
}
void MeshDataInstance::SetRayTracingData()
void ModelDataInstance::SetRayTracingData()
{
if (!m_model)
{
@@ -993,7 +999,7 @@ namespace AZ
rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes);
}
void MeshDataInstance::RemoveRayTracingData()
void ModelDataInstance::RemoveRayTracingData()
{
// remove from ray tracing
RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
@@ -1003,7 +1009,7 @@ namespace AZ
}
}
void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
void ModelDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
{
m_sortKey = sortKey;
for (auto& drawPacketList : m_drawPacketListsByLod)
@@ -1015,24 +1021,24 @@ namespace AZ
}
}
RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const
RHI::DrawItemSortKey ModelDataInstance::GetSortKey() const
{
return m_sortKey;
}
void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
void ModelDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
{
m_cullable.m_lodData.m_lodConfiguration = meshLodConfig;
}
RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const
RPI::Cullable::LodConfiguration ModelDataInstance::GetMeshLodConfiguration() const
{
return m_cullable.m_lodData.m_lodConfiguration;
}
void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
{
AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance:: UpdateDrawPackets");
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets");
for (auto& drawPacketList : m_drawPacketListsByLod)
{
for (auto& drawPacket : drawPacketList)
@@ -1045,9 +1051,9 @@ namespace AZ
}
}
void MeshDataInstance::BuildCullable()
void ModelDataInstance::BuildCullable()
{
AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: BuildCullable");
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable");
AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1122,9 +1128,9 @@ namespace AZ
m_cullBoundsNeedsUpdate = true;
}
void MeshDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
{
AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: UpdateCullBounds");
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds");
AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1148,74 +1154,74 @@ namespace AZ
m_cullBoundsNeedsUpdate = false;
}
void MeshDataInstance::UpdateObjectSrg()
void ModelDataInstance::UpdateObjectSrg()
{
if (!m_shaderResourceGroup)
for (auto& objectSrg : m_objectSrgList)
{
return;
ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor<ReflectionProbeFeatureProcessor>();
if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
{
// retrieve probe constant indices
AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld"));
AZ_Error("ModelDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse"));
AZ_Error("ModelDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths"));
AZ_Error("ModelDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths"));
AZ_Error("ModelDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe"));
AZ_Error("ModelDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
AZ_Error("ModelDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
AZ_Error("ModelDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
// retrieve probe cubemap index
Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = objectSrg->FindShaderInputImageIndex(reflectionCubeMapImageName);
AZ_Error("ModelDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr());
// retrieve the list of probes that contain the centerpoint of the mesh
TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor<TransformServiceFeatureProcessor>();
Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes;
reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes);
if (!reflectionProbes.empty() && reflectionProbes[0])
{
objectSrg->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform());
objectSrg->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull());
objectSrg->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths());
objectSrg->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths());
objectSrg->SetConstant(useReflectionProbeConstantIndex, true);
objectSrg->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection());
objectSrg->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure());
objectSrg->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage());
}
else
{
objectSrg->SetConstant(useReflectionProbeConstantIndex, false);
}
}
objectSrg->Compile();
}
ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor<ReflectionProbeFeatureProcessor>();
if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
{
// retrieve probe constant indices
AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld"));
AZ_Error("MeshDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse"));
AZ_Error("MeshDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths"));
AZ_Error("MeshDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths"));
AZ_Error("MeshDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe"));
AZ_Error("MeshDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
// retrieve probe cubemap index
Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName);
AZ_Error("MeshDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr());
// retrieve the list of probes that contain the centerpoint of the mesh
TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor<TransformServiceFeatureProcessor>();
Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes;
reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes);
if (!reflectionProbes.empty() && reflectionProbes[0])
{
m_shaderResourceGroup->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform());
m_shaderResourceGroup->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull());
m_shaderResourceGroup->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths());
m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths());
m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true);
m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection());
m_shaderResourceGroup->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure());
m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage());
}
else
{
m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, false);
}
}
m_shaderResourceGroup->Compile();
m_objectSrgNeedsUpdate = false;
// Set m_objectSrgNeedsUpdate to false if there are object SRGs in the list
m_objectSrgNeedsUpdate = m_objectSrgNeedsUpdate && (m_objectSrgList.size() == 0);
}
bool MeshDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance<RPI::Material> material) const
bool ModelDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance<RPI::Material> material) const
{
// look for a shader that has the o_materialUseForwardPassIBLSpecular option set
// Note: this should be changed to have the material automatically set the forwardPassIBLSpecular
@@ -1241,7 +1247,7 @@ namespace AZ
return false;
}
void MeshDataInstance::SetVisible(bool isVisible)
void ModelDataInstance::SetVisible(bool isVisible)
{
m_visible = isVisible;
m_cullable.m_isHidden = !isVisible;
@@ -95,13 +95,13 @@ namespace AZ
renderProxy.m_instance->m_model->WaitForUpload();
}
//Note: we are creating pointers to the meshDataInstance cullpacket and lod packet here,
//Note: we are creating pointers to the modelDataInstance cullpacket and lod packet here,
//and holding them until the skinnedMeshDispatchItems are dispatched. There is an assumption that the underlying
//data will not move during this phase.
MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle;
m_workgroup.m_cullPackets.push_back(&meshDataInstance.GetCullPacket());
m_workgroup.m_drawListMask |= meshDataInstance.GetCullPacket().m_drawListMask;
m_lodPackets.push_back(&meshDataInstance.GetLodPacket());
ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle;
m_workgroup.m_cullPackets.push_back(&modelDataInstance.GetCullPacket());
m_workgroup.m_drawListMask |= modelDataInstance.GetCullPacket().m_drawListMask;
m_lodPackets.push_back(&modelDataInstance.GetLodPacket());
m_potentiallyVisibleProxies.push_back(&renderProxy);
}
}
@@ -187,8 +187,8 @@ namespace AZ
renderProxy.m_instance->m_model->WaitForUpload();
}
MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle;
const RPI::Cullable& cullable = meshDataInstance.GetCullable();
ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle;
const RPI::Cullable& cullable = modelDataInstance.GetCullable();
for (const RPI::ViewPtr& viewPtr : packet.m_views)
{
@@ -880,12 +880,14 @@ namespace AZ
{
if (m_meshHandle)
{
Data::Instance<RPI::ShaderResourceGroup> wrinkleMaskObjectSrg = m_meshFeatureProcessor->GetObjectSrg(*m_meshHandle);
if (wrinkleMaskObjectSrg)
const AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>>& wrinkleMaskObjectSrgs = m_meshFeatureProcessor->GetObjectSrgs(*m_meshHandle);
for (auto& wrinkleMaskObjectSrg : wrinkleMaskObjectSrgs)
{
RHI::ShaderInputImageIndex wrinkleMasksIndex = wrinkleMaskObjectSrg->FindShaderInputImageIndex(Name{ "m_wrinkle_masks" });
RHI::ShaderInputConstantIndex wrinkleMaskWeightsIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_weights" });
RHI::ShaderInputConstantIndex wrinkleMaskCountIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_count" });
if (wrinkleMasksIndex.IsValid() || wrinkleMaskWeightsIndex.IsValid() || wrinkleMaskCountIndex.IsValid())
{
AZ_Error("AtomActorInstance", wrinkleMasksIndex.IsValid(), "m_wrinkle_masks not found on the ObjectSrg, but m_wrinkle_mask_weights and/or m_wrinkle_mask_count are being used.");