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 ae61d25f948d..3c243eed590b 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 @@ -132,6 +132,9 @@ namespace AZ virtual void ConnectMeshDrawPacketUpdatedHandler(MeshDrawPacketUpdatedEvent::Handler& handler) = 0; virtual CustomMaterialInfo GetCustomMaterialWithFallback(const CustomMaterialId& id) const = 0; + + //! Returns lodIndex * 32 + meshIndex, the value placed in DrawSrg::m_meshInfoIndex per draw call. + virtual int32_t GetMeshInfoIndex(size_t modelLodIndex, size_t meshIndex) const = 0; }; using CustomMaterialMap = AZStd::unordered_map; diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 7adcda43513c..43a867ca26d7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -2197,7 +2197,13 @@ namespace AZ if (!r_meshInstancingEnabled || instanceGroupInsertResult.m_instanceCount == 1) { // setup the mesh draw packet - RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, customMaterialInfo.m_uvMapping); + RPI::MeshDrawPacket drawPacket( + modelLod, + meshIndex, + GetMeshInfoIndex(modelLodIndex, meshIndex), + material, + meshObjectSrg, + customMaterialInfo.m_uvMapping); // set the shader option to select forward pass IBL specular if necessary if (!drawPacket.SetShaderOption(s_o_meshUseForwardPassIBLSpecular_Name, AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular })) @@ -3146,5 +3152,15 @@ namespace AZ handler.Connect(m_meshDrawPacketUpdatedEvent); } + int32_t ModelDataInstance::GetMeshInfoIndex(size_t modelLodIndex, size_t meshIndex) const + { + // Simplified version of the function from PR #19123 + // Indexes all submeshes in a globally unique way. + static constexpr uint32_t MeshInfoIndexMeshesPerLod = 32; + static constexpr uint32_t MeshInfoIndicesPerMesh = MeshInfoIndexMeshesPerLod * RPI::ModelLodAsset::LodCountMax; + return static_cast( + m_objectId.GetIndex() * MeshInfoIndicesPerMesh + modelLodIndex * MeshInfoIndexMeshesPerLod + meshIndex); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.h index 46f7a9d735ca..8dde762754ea 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.h @@ -115,6 +115,7 @@ namespace AZ void BuildDrawPacketList(MeshFeatureProcessor* meshFeatureProcessor, size_t modelLodIndex); void SetRayTracingData(MeshFeatureProcessor* meshFeatureProcessor); void RemoveRayTracingData(RayTracingFeatureProcessor* rayTracingFeatureProcessor); + int32_t GetMeshInfoIndex(size_t modelLodIndex, size_t meshIndex) const override; void SetIrradianceData( RayTracingFeatureProcessor::SubMesh& subMesh, const Data::Instance material, diff --git a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli index fe862dfd10a5..0b7ebc0198f9 100644 --- a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli +++ b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli @@ -28,6 +28,7 @@ ShaderResourceGroup DrawSrg : SRG_PerDraw { // This SRG is unique per draw packet uint m_uvStreamTangentBitmask; + uint m_meshInfoIndex; #if USE_DRAWSRG_MESHLOD_MESHINDEX // See MeshDrawPacket.h diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/MeshDrawPacket.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/MeshDrawPacket.h index 7d086fb7a32d..9f3390d44d15 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/MeshDrawPacket.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/MeshDrawPacket.h @@ -53,6 +53,7 @@ namespace AZ MeshDrawPacket( ModelLod& modelLod, size_t modelLodMeshIndex, + int32_t meshInfoIndex, Data::Instance materialOverride, Data::Instance objectSrg, const MaterialModelUvOverrideMap& materialModelUvMap = {}); @@ -119,6 +120,9 @@ namespace AZ // The index of the mesh within m_modelLod that is represented by the DrawPacket size_t m_modelLodMeshIndex; + // Compact LOD-stable index: lodIndex * 32 + meshIndex. See ModelDataInstance::GetMeshInfoIndex. + int32_t m_meshInfoIndex = -1; + // The per-object shader resource group Data::Instance m_objectSrg; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp index 132465b3a967..587e7cf1da0e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp @@ -34,12 +34,14 @@ namespace AZ MeshDrawPacket::MeshDrawPacket( ModelLod& modelLod, size_t modelLodMeshIndex, + int32_t meshInfoIndex, Data::Instance materialOverride, Data::Instance objectSrg, const MaterialModelUvOverrideMap& materialModelUvMap ) : m_modelLod(&modelLod) , m_modelLodMeshIndex(modelLodMeshIndex) + , m_meshInfoIndex(meshInfoIndex) , m_objectSrg(objectSrg) , m_material(materialOverride) , m_materialModelUvMap(materialModelUvMap) @@ -441,6 +443,16 @@ namespace AZ drawSrg->SetConstant(index, aznumeric_cast(m_modelLodMeshIndex)); } + if (m_meshInfoIndex >= 0) + { + AZ::Name meshInfoNameIdx("m_meshInfoIndex"); + auto meshInfoConstIdx = drawSrg->FindShaderInputConstantIndex(meshInfoNameIdx); + if (meshInfoConstIdx.IsValid()) + { + drawSrg->SetConstant(meshInfoConstIdx, aznumeric_cast(m_meshInfoIndex)); + } + } + // TODO: Does it make sense to call Compile() in the case where both SetConstant() calls above fail? // Leaving it as always calling Compile() as precaution that there's code somewhere else that assumes // Compile() was already called on DrawSrg.