diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 2ac184e2e0..23cd76ca20 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -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& modelAsset, MeshDataInstance* parent); + MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent); ~MeshLoader(); ModelChangedEvent& GetModelChangedEvent(); @@ -68,7 +68,7 @@ namespace AZ } }; MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent; Data::Asset 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 m_originalModelAsset; - Data::Instance m_shaderResourceGroup; + //! List of object SRGs used by meshes in this model + AZStd::vector> m_objectSrgList; AZStd::unique_ptr m_meshLoader; RPI::Scene* m_scene = nullptr; RHI::DrawItemSortKey m_sortKey; @@ -152,7 +153,7 @@ namespace AZ Data::Instance GetModel(const MeshHandle& meshHandle) const override; Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override; - Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const override; + const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override; void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override; void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& 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 m_meshData; + StableDynamicArray m_modelData; TransformServiceFeatureProcessor* m_transformService; RayTracingFeatureProcessor* m_rayTracingFeatureProcessor = nullptr; AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index cffbe5c3c5..356b1936ca 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -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; + using MeshHandle = StableDynamicArrayHandle; using ModelChangedEvent = Event>; //! Acquires a model with an optional collection of material assignments. @@ -61,12 +61,15 @@ namespace AZ virtual Data::Instance GetModel(const MeshHandle& meshHandle) const = 0; //! Gets the underlying RPI::ModelAsset for a meshHandle. virtual Data::Asset 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 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>& 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. diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 35e399997f..2c818d3c9b 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -19,7 +19,7 @@ namespace UnitTest MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&)); MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&)); MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&)); - MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr(const MeshHandle&)); + MOCK_CONST_METHOD1(GetObjectSrgs, const AZStd::vector>&(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&)); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 99f01ea630..112eff64a8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -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(descriptor.m_modelAsset, &*meshDataHandle); + meshDataHandle->m_meshLoader = AZStd::make_unique(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 MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const + const AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const { - return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr; + static AZStd::vector> 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& modelAsset, MeshDataInstance* parent) + // ModelDataInstance::MeshLoader... + ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset& 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 asset) + void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset asset) { Data::Asset 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 asset) + void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset) { OnAssetReady(asset); } - void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset asset) + void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset 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 model) + void ModelDataInstance::Init(Data::Instance 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 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(); @@ -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(); + + 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(); + 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(); - - 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(); - 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 material) const + bool ModelDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance 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; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index 4c379c4239..c135b017fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -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) { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index a3161002a0..a3978c2d03 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -880,12 +880,14 @@ namespace AZ { if (m_meshHandle) { - Data::Instance wrinkleMaskObjectSrg = m_meshFeatureProcessor->GetObjectSrg(*m_meshHandle); - if (wrinkleMaskObjectSrg) + const AZStd::vector>& 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.");