RayTracingFeatureProcessor.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <RayTracing/RayTracingFeatureProcessor.h>
  9. #include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
  10. #include <Atom/RHI/Factory.h>
  11. #include <Atom/RHI/RHISystemInterface.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/RPI.Public/Pass/PassFilter.h>
  14. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  15. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  16. #include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h>
  17. #include <CoreLights/DirectionalLightFeatureProcessor.h>
  18. #include <CoreLights/SimplePointLightFeatureProcessor.h>
  19. #include <CoreLights/SimpleSpotLightFeatureProcessor.h>
  20. #include <CoreLights/PointLightFeatureProcessor.h>
  21. #include <CoreLights/DiskLightFeatureProcessor.h>
  22. #include <CoreLights/CapsuleLightFeatureProcessor.h>
  23. #include <CoreLights/QuadLightFeatureProcessor.h>
  24. namespace AZ
  25. {
  26. namespace Render
  27. {
  28. void RayTracingFeatureProcessor::Reflect(ReflectContext* context)
  29. {
  30. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  31. {
  32. serializeContext
  33. ->Class<RayTracingFeatureProcessor, FeatureProcessor>()
  34. ->Version(1);
  35. }
  36. }
  37. void RayTracingFeatureProcessor::Activate()
  38. {
  39. RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
  40. m_rayTracingEnabled = device->GetFeatures().m_rayTracing;
  41. if (!m_rayTracingEnabled)
  42. {
  43. return;
  44. }
  45. m_transformServiceFeatureProcessor = GetParentScene()->GetFeatureProcessor<TransformServiceFeatureProcessor>();
  46. // initialize the ray tracing buffer pools
  47. m_bufferPools = RHI::RayTracingBufferPools::CreateRHIRayTracingBufferPools();
  48. m_bufferPools->Init(device);
  49. // create TLAS attachmentId
  50. AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
  51. m_tlasAttachmentId = RHI::AttachmentId(AZStd::string::format("RayTracingTlasAttachmentId_%s", uuidString.c_str()));
  52. // create the TLAS object
  53. m_tlas = AZ::RHI::RayTracingTlas::CreateRHIRayTracingTlas();
  54. // load the RayTracingSrg asset asset
  55. m_rayTracingSrgAsset = RPI::AssetUtils::LoadCriticalAsset<RPI::ShaderAsset>("shaderlib/atom/features/rayTracing/raytracingsrgs.azshader");
  56. if (!m_rayTracingSrgAsset.IsReady())
  57. {
  58. AZ_Assert(false, "Failed to load RayTracingSrg asset");
  59. return;
  60. }
  61. // create the RayTracingSceneSrg
  62. m_rayTracingSceneSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingSceneSrg"));
  63. AZ_Assert(m_rayTracingSceneSrg, "Failed to create RayTracingSceneSrg");
  64. // create the RayTracingMaterialSrg
  65. const AZ::Name rayTracingMaterialSrgName("RayTracingMaterialSrg");
  66. m_rayTracingMaterialSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingMaterialSrg"));
  67. AZ_Assert(m_rayTracingMaterialSrg, "Failed to create RayTracingMaterialSrg");
  68. EnableSceneNotification();
  69. }
  70. void RayTracingFeatureProcessor::Deactivate()
  71. {
  72. DisableSceneNotification();
  73. }
  74. void RayTracingFeatureProcessor::AddMesh(const AZ::Uuid& uuid, const Mesh& rayTracingMesh, const SubMeshVector& subMeshes)
  75. {
  76. if (!m_rayTracingEnabled)
  77. {
  78. return;
  79. }
  80. RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
  81. // lock the mutex to protect the mesh and BLAS lists
  82. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  83. // check to see if we already have this mesh
  84. MeshMap::iterator itMesh = m_meshes.find(uuid);
  85. if (itMesh != m_meshes.end())
  86. {
  87. AZ_Assert(false, "AddMesh called on an existing Mesh, call RemoveMesh first");
  88. return;
  89. }
  90. // add the mesh
  91. m_meshes.insert(AZStd::make_pair(uuid, rayTracingMesh));
  92. Mesh& mesh = m_meshes[uuid];
  93. // add the subMeshes to the end of the global subMesh vector
  94. // Note 1: the MeshInfo and MaterialInfo vectors are parallel with the subMesh vector
  95. // Note 2: the list of indices for the subMeshes in the global vector are stored in the parent Mesh
  96. IndexVector subMeshIndices;
  97. uint32_t subMeshGlobalIndex = aznumeric_cast<uint32_t>(m_subMeshes.size());
  98. for (uint32_t subMeshIndex = 0; subMeshIndex < subMeshes.size(); ++subMeshIndex, ++subMeshGlobalIndex)
  99. {
  100. SubMesh& subMesh = m_subMeshes.emplace_back(subMeshes[subMeshIndex]);
  101. subMesh.m_mesh = &mesh;
  102. subMesh.m_subMeshIndex = subMeshIndex;
  103. subMesh.m_globalIndex = subMeshGlobalIndex;
  104. // add to the list of global subMeshIndices, which will be stored in the Mesh
  105. subMeshIndices.push_back(subMeshGlobalIndex);
  106. // add MeshInfo and MaterialInfo entries
  107. m_meshInfos.emplace_back();
  108. m_materialInfos.emplace_back();
  109. }
  110. mesh.m_subMeshIndices = subMeshIndices;
  111. // search for an existing BLAS instance entry for this mesh using the assetId
  112. BlasInstanceMap::iterator itMeshBlasInstance = m_blasInstanceMap.find(mesh.m_assetId);
  113. if (itMeshBlasInstance == m_blasInstanceMap.end())
  114. {
  115. // make a new BLAS map entry for this mesh
  116. MeshBlasInstance meshBlasInstance;
  117. meshBlasInstance.m_count = 1;
  118. meshBlasInstance.m_subMeshes.reserve(mesh.m_subMeshIndices.size());
  119. itMeshBlasInstance = m_blasInstanceMap.insert({ mesh.m_assetId, meshBlasInstance }).first;
  120. }
  121. else
  122. {
  123. itMeshBlasInstance->second.m_count++;
  124. }
  125. // create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created.
  126. // Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases)
  127. // Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass
  128. [[maybe_unused]] bool blasInstanceFound = false;
  129. for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshIndices.size(); ++subMeshIndex)
  130. {
  131. SubMesh& subMesh = m_subMeshes[mesh.m_subMeshIndices[subMeshIndex]];
  132. RHI::RayTracingBlasDescriptor blasDescriptor;
  133. blasDescriptor.Build()
  134. ->Geometry()
  135. ->VertexFormat(subMesh.m_positionFormat)
  136. ->VertexBuffer(subMesh.m_positionVertexBufferView)
  137. ->IndexBuffer(subMesh.m_indexBufferView)
  138. ;
  139. // determine if we have an existing BLAS object for this subMesh
  140. if (itMeshBlasInstance->second.m_subMeshes.size() >= subMeshIndex + 1)
  141. {
  142. // re-use existing BLAS
  143. subMesh.m_blas = itMeshBlasInstance->second.m_subMeshes[subMeshIndex].m_blas;
  144. // keep track of the fact that we re-used a BLAS
  145. blasInstanceFound = true;
  146. }
  147. else
  148. {
  149. AZ_Assert(blasInstanceFound == false, "Partial set of RayTracingBlas objects found for mesh");
  150. // create the BLAS object and store it in the BLAS list
  151. RHI::Ptr<RHI::RayTracingBlas> rayTracingBlas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas();
  152. itMeshBlasInstance->second.m_subMeshes.push_back({ rayTracingBlas });
  153. // create the buffers from the BLAS descriptor
  154. rayTracingBlas->CreateBuffers(*device, &blasDescriptor, *m_bufferPools);
  155. // store the BLAS in the mesh
  156. subMesh.m_blas = rayTracingBlas;
  157. }
  158. }
  159. AZ::Transform noScaleTransform = mesh.m_transform;
  160. noScaleTransform.ExtractUniformScale();
  161. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  162. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  163. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  164. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  165. // store the mesh buffers and material textures in the resource lists
  166. for (uint32_t subMeshIndex : mesh.m_subMeshIndices)
  167. {
  168. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  169. MeshInfo& meshInfo = m_meshInfos[subMesh.m_globalIndex];
  170. MaterialInfo& materialInfo = m_materialInfos[subMesh.m_globalIndex];
  171. subMesh.m_irradianceColor.StoreToFloat4(meshInfo.m_irradianceColor.data());
  172. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  173. meshInfo.m_bufferFlags = subMesh.m_bufferFlags;
  174. AZ_Assert(subMesh.m_indexShaderBufferView.get(), "RayTracing Mesh IndexBuffer cannot be null");
  175. AZ_Assert(subMesh.m_positionShaderBufferView.get(), "RayTracing Mesh PositionBuffer cannot be null");
  176. AZ_Assert(subMesh.m_normalShaderBufferView.get(), "RayTracing Mesh NormalBuffer cannot be null");
  177. // add mesh buffers
  178. meshInfo.m_bufferStartIndex = m_meshBufferIndices.AddEntry(
  179. {
  180. #if USE_BINDLESS_SRG
  181. subMesh.m_indexShaderBufferView.get() ? subMesh.m_indexShaderBufferView->GetBindlessReadIndex() : InvalidIndex,
  182. subMesh.m_positionShaderBufferView.get() ? subMesh.m_positionShaderBufferView->GetBindlessReadIndex() : InvalidIndex,
  183. subMesh.m_normalShaderBufferView.get() ? subMesh.m_normalShaderBufferView->GetBindlessReadIndex() : InvalidIndex,
  184. subMesh.m_tangentShaderBufferView.get() ? subMesh.m_tangentShaderBufferView->GetBindlessReadIndex() : InvalidIndex,
  185. subMesh.m_bitangentShaderBufferView.get() ? subMesh.m_bitangentShaderBufferView->GetBindlessReadIndex() : InvalidIndex,
  186. subMesh.m_uvShaderBufferView.get() ? subMesh.m_uvShaderBufferView->GetBindlessReadIndex() : InvalidIndex
  187. #else
  188. m_meshBuffers.AddResource(subMesh.m_indexShaderBufferView.get()),
  189. m_meshBuffers.AddResource(subMesh.m_positionShaderBufferView.get()),
  190. m_meshBuffers.AddResource(subMesh.m_normalShaderBufferView.get()),
  191. m_meshBuffers.AddResource(subMesh.m_tangentShaderBufferView.get()),
  192. m_meshBuffers.AddResource(subMesh.m_bitangentShaderBufferView.get()),
  193. m_meshBuffers.AddResource(subMesh.m_uvShaderBufferView.get())
  194. #endif
  195. });
  196. meshInfo.m_indexByteOffset = subMesh.m_indexBufferView.GetByteOffset();
  197. meshInfo.m_positionByteOffset = subMesh.m_positionVertexBufferView.GetByteOffset();
  198. meshInfo.m_normalByteOffset = subMesh.m_normalVertexBufferView.GetByteOffset();
  199. meshInfo.m_tangentByteOffset = subMesh.m_tangentShaderBufferView ? subMesh.m_tangentVertexBufferView.GetByteOffset() : 0;
  200. meshInfo.m_bitangentByteOffset = subMesh.m_bitangentShaderBufferView ? subMesh.m_bitangentVertexBufferView.GetByteOffset() : 0;
  201. meshInfo.m_uvByteOffset = subMesh.m_uvShaderBufferView ? subMesh.m_uvVertexBufferView.GetByteOffset() : 0;
  202. // add material textures
  203. subMesh.m_baseColor.StoreToFloat4(materialInfo.m_baseColor.data());
  204. subMesh.m_emissiveColor.StoreToFloat4(materialInfo.m_emissiveColor.data());
  205. materialInfo.m_metallicFactor = subMesh.m_metallicFactor;
  206. materialInfo.m_roughnessFactor = subMesh.m_roughnessFactor;
  207. materialInfo.m_textureFlags = subMesh.m_textureFlags;
  208. materialInfo.m_textureStartIndex = m_materialTextureIndices.AddEntry(
  209. {
  210. #if USE_BINDLESS_SRG
  211. subMesh.m_baseColorImageView.get() ? subMesh.m_baseColorImageView->GetBindlessReadIndex() : InvalidIndex,
  212. subMesh.m_normalImageView.get() ? subMesh.m_normalImageView->GetBindlessReadIndex() : InvalidIndex,
  213. subMesh.m_metallicImageView.get() ? subMesh.m_metallicImageView->GetBindlessReadIndex() : InvalidIndex,
  214. subMesh.m_roughnessImageView.get() ? subMesh.m_roughnessImageView->GetBindlessReadIndex() : InvalidIndex,
  215. subMesh.m_emissiveImageView.get() ? subMesh.m_emissiveImageView->GetBindlessReadIndex() : InvalidIndex
  216. #else
  217. m_materialTextures.AddResource(subMesh.m_baseColorImageView.get()),
  218. m_materialTextures.AddResource(subMesh.m_normalImageView.get()),
  219. m_materialTextures.AddResource(subMesh.m_metallicImageView.get()),
  220. m_materialTextures.AddResource(subMesh.m_roughnessImageView.get()),
  221. m_materialTextures.AddResource(subMesh.m_emissiveImageView.get())
  222. #endif
  223. });
  224. // add reflection probe data
  225. if (mesh.m_reflectionProbe.m_reflectionProbeCubeMap.get())
  226. {
  227. materialInfo.m_reflectionProbeCubeMapIndex = mesh.m_reflectionProbe.m_reflectionProbeCubeMap->GetImageView()->GetBindlessReadIndex();
  228. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  229. {
  230. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  231. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  232. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  233. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  234. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  235. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  236. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  237. }
  238. }
  239. }
  240. m_revision++;
  241. m_subMeshCount += aznumeric_cast<uint32_t>(subMeshes.size());
  242. m_meshInfoBufferNeedsUpdate = true;
  243. m_materialInfoBufferNeedsUpdate = true;
  244. m_indexListNeedsUpdate = true;
  245. }
  246. void RayTracingFeatureProcessor::RemoveMesh(const AZ::Uuid& uuid)
  247. {
  248. if (!m_rayTracingEnabled)
  249. {
  250. return;
  251. }
  252. // lock the mutex to protect the mesh and BLAS lists
  253. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  254. MeshMap::iterator itMesh = m_meshes.find(uuid);
  255. if (itMesh != m_meshes.end())
  256. {
  257. Mesh& mesh = itMesh->second;
  258. // decrement the count from the BLAS instances, and check to see if we can remove them
  259. BlasInstanceMap::iterator itBlas = m_blasInstanceMap.find(mesh.m_assetId);
  260. if (itBlas != m_blasInstanceMap.end())
  261. {
  262. itBlas->second.m_count--;
  263. if (itBlas->second.m_count == 0)
  264. {
  265. m_blasInstanceMap.erase(itBlas);
  266. }
  267. }
  268. // remove the SubMeshes
  269. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  270. {
  271. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  272. uint32_t globalIndex = subMesh.m_globalIndex;
  273. MeshInfo& meshInfo = m_meshInfos[globalIndex];
  274. MaterialInfo& materialInfo = m_materialInfos[globalIndex];
  275. m_meshBufferIndices.RemoveEntry(meshInfo.m_bufferStartIndex);
  276. m_materialTextureIndices.RemoveEntry(materialInfo.m_textureStartIndex);
  277. #if !USE_BINDLESS_SRG
  278. m_meshBuffers.RemoveResource(subMesh.m_indexShaderBufferView.get());
  279. m_meshBuffers.RemoveResource(subMesh.m_positionShaderBufferView.get());
  280. m_meshBuffers.RemoveResource(subMesh.m_normalShaderBufferView.get());
  281. m_meshBuffers.RemoveResource(subMesh.m_tangentShaderBufferView.get());
  282. m_meshBuffers.RemoveResource(subMesh.m_bitangentShaderBufferView.get());
  283. m_meshBuffers.RemoveResource(subMesh.m_uvShaderBufferView.get());
  284. m_materialTextures.RemoveResource(subMesh.m_baseColorImageView.get());
  285. m_materialTextures.RemoveResource(subMesh.m_normalImageView.get());
  286. m_materialTextures.RemoveResource(subMesh.m_metallicImageView.get());
  287. m_materialTextures.RemoveResource(subMesh.m_roughnessImageView.get());
  288. m_materialTextures.RemoveResource(subMesh.m_emissiveImageView.get());
  289. #endif
  290. if (globalIndex < m_subMeshes.size() - 1)
  291. {
  292. // the subMesh we're removing is in the middle of the global lists, remove by swapping the last element to its position in the list
  293. m_subMeshes[globalIndex] = m_subMeshes.back();
  294. m_meshInfos[globalIndex] = m_meshInfos.back();
  295. m_materialInfos[globalIndex] = m_materialInfos.back();
  296. // update the global index for the swapped subMesh
  297. m_subMeshes[globalIndex].m_globalIndex = globalIndex;
  298. // update the global index in the parent Mesh' subMesh list
  299. Mesh* swappedSubMeshParent = m_subMeshes[globalIndex].m_mesh;
  300. uint32_t swappedSubMeshIndex = m_subMeshes[globalIndex].m_subMeshIndex;
  301. swappedSubMeshParent->m_subMeshIndices[swappedSubMeshIndex] = globalIndex;
  302. }
  303. m_subMeshes.pop_back();
  304. m_meshInfos.pop_back();
  305. m_materialInfos.pop_back();
  306. }
  307. // remove from the Mesh list
  308. m_subMeshCount -= aznumeric_cast<uint32_t>(mesh.m_subMeshIndices.size());
  309. m_meshes.erase(itMesh);
  310. m_revision++;
  311. // reset all data structures if all meshes were removed (i.e., empty scene)
  312. if (m_subMeshCount == 0)
  313. {
  314. m_meshes.clear();
  315. m_subMeshes.clear();
  316. m_meshInfos.clear();
  317. m_materialInfos.clear();
  318. m_meshBufferIndices.Reset();
  319. m_materialTextureIndices.Reset();
  320. #if !USE_BINDLESS_SRG
  321. m_meshBuffers.Reset();
  322. m_materialTextures.Reset();
  323. #endif
  324. }
  325. }
  326. m_meshInfoBufferNeedsUpdate = true;
  327. m_materialInfoBufferNeedsUpdate = true;
  328. m_indexListNeedsUpdate = true;
  329. }
  330. void RayTracingFeatureProcessor::SetMeshTransform(const AZ::Uuid& uuid, const AZ::Transform transform, const AZ::Vector3 nonUniformScale)
  331. {
  332. if (!m_rayTracingEnabled)
  333. {
  334. return;
  335. }
  336. MeshMap::iterator itMesh = m_meshes.find(uuid);
  337. if (itMesh != m_meshes.end())
  338. {
  339. Mesh& mesh = itMesh->second;
  340. mesh.m_transform = transform;
  341. mesh.m_nonUniformScale = nonUniformScale;
  342. m_revision++;
  343. // create a world inverse transpose 3x4 matrix
  344. AZ::Transform noScaleTransform = mesh.m_transform;
  345. noScaleTransform.ExtractUniformScale();
  346. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  347. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  348. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  349. // update all MeshInfos for this Mesh with the new transform
  350. for (const auto& subMeshIndex : mesh.m_subMeshIndices)
  351. {
  352. MeshInfo& meshInfo = m_meshInfos[subMeshIndex];
  353. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  354. }
  355. m_meshInfoBufferNeedsUpdate = true;
  356. }
  357. }
  358. void RayTracingFeatureProcessor::SetMeshReflectionProbe(const AZ::Uuid& uuid, const Mesh::ReflectionProbe& reflectionProbe)
  359. {
  360. if (!m_rayTracingEnabled)
  361. {
  362. return;
  363. }
  364. MeshMap::iterator itMesh = m_meshes.find(uuid);
  365. if (itMesh != m_meshes.end())
  366. {
  367. Mesh& mesh = itMesh->second;
  368. // update the Mesh reflection probe data
  369. mesh.m_reflectionProbe = reflectionProbe;
  370. // update all of the subMeshes
  371. const Data::Instance<RPI::Image>& reflectionProbeCubeMap = reflectionProbe.m_reflectionProbeCubeMap;
  372. uint32_t reflectionProbeCubeMapIndex = reflectionProbeCubeMap.get() ? reflectionProbeCubeMap->GetImageView()->GetBindlessReadIndex() : InvalidIndex;
  373. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  374. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  375. {
  376. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  377. uint32_t globalIndex = subMesh.m_globalIndex;
  378. MaterialInfo& materialInfo = m_materialInfos[globalIndex];
  379. materialInfo.m_reflectionProbeCubeMapIndex = reflectionProbeCubeMapIndex;
  380. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  381. {
  382. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  383. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  384. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  385. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  386. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  387. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  388. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  389. }
  390. else
  391. {
  392. materialInfo.m_reflectionProbeData.m_useReflectionProbe = false;
  393. }
  394. }
  395. m_materialInfoBufferNeedsUpdate = true;
  396. }
  397. }
  398. void RayTracingFeatureProcessor::UpdateRayTracingSrgs()
  399. {
  400. AZ_PROFILE_SCOPE(AzRender, "RayTracingFeatureProcessor::UpdateRayTracingSrgs");
  401. if (!m_tlas->GetTlasBuffer())
  402. {
  403. return;
  404. }
  405. if (m_rayTracingSceneSrg->IsQueuedForCompile() || m_rayTracingMaterialSrg->IsQueuedForCompile())
  406. {
  407. //[GFX TODO][ATOM-14792] AtomSampleViewer: Reset scene and feature processors before switching to sample
  408. return;
  409. }
  410. // lock the mutex to protect the mesh and BLAS lists
  411. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  412. if (m_subMeshCount > 0)
  413. {
  414. UpdateMeshInfoBuffer();
  415. UpdateMaterialInfoBuffer();
  416. UpdateIndexLists();
  417. }
  418. UpdateRayTracingSceneSrg();
  419. UpdateRayTracingMaterialSrg();
  420. }
  421. void RayTracingFeatureProcessor::UpdateMeshInfoBuffer()
  422. {
  423. if (m_meshInfoBufferNeedsUpdate)
  424. {
  425. // advance to the next buffer in the frame list
  426. m_currentMeshInfoFrameIndex = (m_currentMeshInfoFrameIndex + 1) % BufferFrameCount;
  427. // update mesh info buffer
  428. Data::Instance<RPI::Buffer>& currentMeshInfoGpuBuffer = m_meshInfoGpuBuffer[m_currentMeshInfoFrameIndex];
  429. uint32_t newMeshByteCount = m_subMeshCount * sizeof(MeshInfo);
  430. if (currentMeshInfoGpuBuffer == nullptr)
  431. {
  432. // allocate the MeshInfo structured buffer
  433. RPI::CommonBufferDescriptor desc;
  434. desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  435. desc.m_bufferName = "RayTracingMeshInfo";
  436. desc.m_byteCount = newMeshByteCount;
  437. desc.m_elementSize = sizeof(MeshInfo);
  438. currentMeshInfoGpuBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  439. }
  440. else if (currentMeshInfoGpuBuffer->GetBufferSize() < newMeshByteCount)
  441. {
  442. // resize for the new sub-mesh count
  443. currentMeshInfoGpuBuffer->Resize(newMeshByteCount);
  444. }
  445. currentMeshInfoGpuBuffer->UpdateData(m_meshInfos.data(), newMeshByteCount);
  446. m_meshInfoBufferNeedsUpdate = false;
  447. }
  448. }
  449. void RayTracingFeatureProcessor::UpdateMaterialInfoBuffer()
  450. {
  451. if (m_materialInfoBufferNeedsUpdate)
  452. {
  453. // advance to the next buffer in the frame list
  454. m_currentMaterialInfoFrameIndex = (m_currentMaterialInfoFrameIndex + 1) % BufferFrameCount;
  455. // update MaterialInfo buffer
  456. Data::Instance<RPI::Buffer>& currentMaterialInfoGpuBuffer = m_materialInfoGpuBuffer[m_currentMaterialInfoFrameIndex];
  457. uint32_t newMaterialInfoByteCount = m_subMeshCount * sizeof(MaterialInfo);
  458. if (currentMaterialInfoGpuBuffer == nullptr)
  459. {
  460. // allocate the MaterialInfo structured buffer
  461. RPI::CommonBufferDescriptor desc;
  462. desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  463. desc.m_bufferName = "RayTracingMaterialInfo";
  464. desc.m_byteCount = newMaterialInfoByteCount;
  465. desc.m_elementSize = sizeof(MaterialInfo);
  466. currentMaterialInfoGpuBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  467. }
  468. else if (currentMaterialInfoGpuBuffer->GetBufferSize() < newMaterialInfoByteCount)
  469. {
  470. // resize for the new sub-mesh count
  471. currentMaterialInfoGpuBuffer->Resize(newMaterialInfoByteCount);
  472. }
  473. currentMaterialInfoGpuBuffer->UpdateData(m_materialInfos.data(), newMaterialInfoByteCount);
  474. m_materialInfoBufferNeedsUpdate = false;
  475. }
  476. }
  477. void RayTracingFeatureProcessor::UpdateIndexLists()
  478. {
  479. if (m_indexListNeedsUpdate)
  480. {
  481. // advance to the next buffer in the frame list
  482. m_currentIndexListFrameIndex = (m_currentIndexListFrameIndex + 1) % BufferFrameCount;
  483. // update mesh buffer indices buffer
  484. Data::Instance<RPI::Buffer>& currentMeshBufferIndicesGpuBuffer = m_meshBufferIndicesGpuBuffer[m_currentIndexListFrameIndex];
  485. uint32_t newMeshBufferIndicesByteCount = aznumeric_cast<uint32_t>(m_meshBufferIndices.GetIndexList().size()) * sizeof(uint32_t);
  486. if (currentMeshBufferIndicesGpuBuffer == nullptr)
  487. {
  488. // allocate the MeshBufferIndices buffer
  489. RPI::CommonBufferDescriptor desc;
  490. desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  491. desc.m_bufferName = "RayTracingMeshBufferIndices";
  492. desc.m_byteCount = newMeshBufferIndicesByteCount;
  493. desc.m_elementSize = sizeof(IndexVector::value_type);
  494. desc.m_elementFormat = RHI::Format::R32_UINT;
  495. currentMeshBufferIndicesGpuBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  496. }
  497. else if (currentMeshBufferIndicesGpuBuffer->GetBufferSize() < newMeshBufferIndicesByteCount)
  498. {
  499. // resize for the new index count
  500. currentMeshBufferIndicesGpuBuffer->Resize(newMeshBufferIndicesByteCount);
  501. }
  502. #if !USE_BINDLESS_SRG
  503. // resolve to the true indices using the indirection list
  504. // Note: this is done on the CPU to avoid double-indirection in the shader
  505. IndexVector resolvedMeshBufferIndices(m_meshBufferIndices.GetIndexList().size());
  506. uint32_t resolvedMeshBufferIndex = 0;
  507. for (auto& meshBufferIndex : m_meshBufferIndices.GetIndexList())
  508. {
  509. if (!m_meshBufferIndices.IsValidIndex(meshBufferIndex))
  510. {
  511. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = InvalidIndex;
  512. }
  513. else
  514. {
  515. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = m_meshBuffers.GetIndirectionList()[meshBufferIndex];
  516. }
  517. }
  518. currentMeshBufferIndicesGpuBuffer->UpdateData(resolvedMeshBufferIndices.data(), newMeshBufferIndicesByteCount);
  519. #else
  520. currentMeshBufferIndicesGpuBuffer->UpdateData(m_meshBufferIndices.GetIndexList().data(), newMeshBufferIndicesByteCount);
  521. #endif
  522. // update material texture indices buffer
  523. Data::Instance<RPI::Buffer>& currentMaterialTextureIndicesGpuBuffer = m_materialTextureIndicesGpuBuffer[m_currentIndexListFrameIndex];
  524. uint32_t newMaterialTextureIndicesByteCount = aznumeric_cast<uint32_t>(m_materialTextureIndices.GetIndexList().size()) * sizeof(uint32_t);
  525. if (currentMaterialTextureIndicesGpuBuffer == nullptr)
  526. {
  527. // allocate the MaterialInfo structured buffer
  528. RPI::CommonBufferDescriptor desc;
  529. desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  530. desc.m_bufferName = "RayTracingMaterialTextureIndices";
  531. desc.m_byteCount = newMaterialTextureIndicesByteCount;
  532. desc.m_elementSize = sizeof(IndexVector::value_type);
  533. desc.m_elementFormat = RHI::Format::R32_UINT;
  534. currentMaterialTextureIndicesGpuBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  535. }
  536. else if (currentMaterialTextureIndicesGpuBuffer->GetBufferSize() < newMaterialTextureIndicesByteCount)
  537. {
  538. // resize for the new index count
  539. currentMaterialTextureIndicesGpuBuffer->Resize(newMaterialTextureIndicesByteCount);
  540. }
  541. #if !USE_BINDLESS_SRG
  542. // resolve to the true indices using the indirection list
  543. // Note: this is done on the CPU to avoid double-indirection in the shader
  544. IndexVector resolvedMaterialTextureIndices(m_materialTextureIndices.GetIndexList().size());
  545. uint32_t resolvedMaterialTextureIndex = 0;
  546. for (auto& materialTextureIndex : m_materialTextureIndices.GetIndexList())
  547. {
  548. if (!m_materialTextureIndices.IsValidIndex(materialTextureIndex))
  549. {
  550. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = InvalidIndex;
  551. }
  552. else
  553. {
  554. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = m_materialTextures.GetIndirectionList()[materialTextureIndex];
  555. }
  556. }
  557. currentMaterialTextureIndicesGpuBuffer->UpdateData(resolvedMaterialTextureIndices.data(), newMaterialTextureIndicesByteCount);
  558. #else
  559. currentMaterialTextureIndicesGpuBuffer->UpdateData(m_materialTextureIndices.GetIndexList().data(), newMaterialTextureIndicesByteCount);
  560. #endif
  561. m_indexListNeedsUpdate = false;
  562. }
  563. }
  564. void RayTracingFeatureProcessor::UpdateRayTracingSceneSrg()
  565. {
  566. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingSceneSrg->GetLayout();
  567. RHI::ShaderInputImageIndex imageIndex;
  568. RHI::ShaderInputBufferIndex bufferIndex;
  569. RHI::ShaderInputConstantIndex constantIndex;
  570. // TLAS
  571. uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(m_tlas->GetTlasBuffer()->GetDescriptor().m_byteCount);
  572. RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(tlasBufferByteCount);
  573. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_scene"));
  574. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_tlas->GetTlasBuffer()->GetBufferView(bufferViewDescriptor).get());
  575. // directional lights
  576. const auto directionalLightFP = GetParentScene()->GetFeatureProcessor<DirectionalLightFeatureProcessor>();
  577. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_directionalLights"));
  578. m_rayTracingSceneSrg->SetBufferView(bufferIndex, directionalLightFP->GetLightBuffer()->GetBufferView());
  579. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_directionalLightCount"));
  580. m_rayTracingSceneSrg->SetConstant(constantIndex, directionalLightFP->GetLightCount());
  581. // simple point lights
  582. const auto simplePointLightFP = GetParentScene()->GetFeatureProcessor<SimplePointLightFeatureProcessor>();
  583. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simplePointLights"));
  584. m_rayTracingSceneSrg->SetBufferView(bufferIndex, simplePointLightFP->GetLightBuffer()->GetBufferView());
  585. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simplePointLightCount"));
  586. m_rayTracingSceneSrg->SetConstant(constantIndex, simplePointLightFP->GetLightCount());
  587. // simple spot lights
  588. const auto simpleSpotLightFP = GetParentScene()->GetFeatureProcessor<SimpleSpotLightFeatureProcessor>();
  589. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simpleSpotLights"));
  590. m_rayTracingSceneSrg->SetBufferView(bufferIndex, simpleSpotLightFP->GetLightBuffer()->GetBufferView());
  591. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simpleSpotLightCount"));
  592. m_rayTracingSceneSrg->SetConstant(constantIndex, simpleSpotLightFP->GetLightCount());
  593. // point lights (sphere)
  594. const auto pointLightFP = GetParentScene()->GetFeatureProcessor<PointLightFeatureProcessor>();
  595. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_pointLights"));
  596. m_rayTracingSceneSrg->SetBufferView(bufferIndex, pointLightFP->GetLightBuffer()->GetBufferView());
  597. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_pointLightCount"));
  598. m_rayTracingSceneSrg->SetConstant(constantIndex, pointLightFP->GetLightCount());
  599. // disk lights
  600. const auto diskLightFP = GetParentScene()->GetFeatureProcessor<DiskLightFeatureProcessor>();
  601. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_diskLights"));
  602. m_rayTracingSceneSrg->SetBufferView(bufferIndex, diskLightFP->GetLightBuffer()->GetBufferView());
  603. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_diskLightCount"));
  604. m_rayTracingSceneSrg->SetConstant(constantIndex, diskLightFP->GetLightCount());
  605. // capsule lights
  606. const auto capsuleLightFP = GetParentScene()->GetFeatureProcessor<CapsuleLightFeatureProcessor>();
  607. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_capsuleLights"));
  608. m_rayTracingSceneSrg->SetBufferView(bufferIndex, capsuleLightFP->GetLightBuffer()->GetBufferView());
  609. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_capsuleLightCount"));
  610. m_rayTracingSceneSrg->SetConstant(constantIndex, capsuleLightFP->GetLightCount());
  611. // quad lights
  612. const auto quadLightFP = GetParentScene()->GetFeatureProcessor<QuadLightFeatureProcessor>();
  613. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_quadLights"));
  614. m_rayTracingSceneSrg->SetBufferView(bufferIndex, quadLightFP->GetLightBuffer()->GetBufferView());
  615. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_quadLightCount"));
  616. m_rayTracingSceneSrg->SetConstant(constantIndex, quadLightFP->GetLightCount());
  617. // diffuse environment map for sky hits
  618. ImageBasedLightFeatureProcessor* imageBasedLightFeatureProcessor = GetParentScene()->GetFeatureProcessor<ImageBasedLightFeatureProcessor>();
  619. if (imageBasedLightFeatureProcessor)
  620. {
  621. imageIndex = srgLayout->FindShaderInputImageIndex(AZ::Name("m_diffuseEnvMap"));
  622. m_rayTracingSceneSrg->SetImage(imageIndex, imageBasedLightFeatureProcessor->GetDiffuseImage());
  623. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblOrientation"));
  624. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetOrientation());
  625. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblExposure"));
  626. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetExposure());
  627. }
  628. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshInfo"));
  629. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshInfoGpuBuffer[m_currentMeshInfoFrameIndex]->GetBufferView());
  630. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshBufferIndices"));
  631. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshBufferIndicesGpuBuffer[m_currentIndexListFrameIndex]->GetBufferView());
  632. #if !USE_BINDLESS_SRG
  633. RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers"));
  634. m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, m_meshBuffers.GetResourceList());
  635. #endif
  636. m_rayTracingSceneSrg->Compile();
  637. }
  638. void RayTracingFeatureProcessor::UpdateRayTracingMaterialSrg()
  639. {
  640. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingMaterialSrg->GetLayout();
  641. RHI::ShaderInputBufferIndex bufferIndex;
  642. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialInfo"));
  643. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialInfoGpuBuffer[m_currentMaterialInfoFrameIndex]->GetBufferView());
  644. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialTextureIndices"));
  645. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialTextureIndicesGpuBuffer[m_currentIndexListFrameIndex]->GetBufferView());
  646. #if !USE_BINDLESS_SRG
  647. RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures"));
  648. m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, m_materialTextures.GetResourceList());
  649. #endif
  650. m_rayTracingMaterialSrg->Compile();
  651. }
  652. void RayTracingFeatureProcessor::OnRenderPipelineChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline, RPI::SceneNotification::RenderPipelineChangeType changeType)
  653. {
  654. if (!m_rayTracingEnabled)
  655. {
  656. return;
  657. }
  658. // only enable the RayTracingAccelerationStructurePass on the first pipeline in this scene, this will avoid multiple updates to the same AS
  659. bool enabled = true;
  660. if (changeType == RPI::SceneNotification::RenderPipelineChangeType::Added
  661. || changeType == RPI::SceneNotification::RenderPipelineChangeType::Removed)
  662. {
  663. AZ::RPI::PassFilter passFilter = AZ::RPI::PassFilter::CreateWithPassName(AZ::Name("RayTracingAccelerationStructurePass"), GetParentScene());
  664. AZ::RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&enabled](AZ::RPI::Pass* pass) -> AZ::RPI::PassFilterExecutionFlow
  665. {
  666. pass->SetEnabled(enabled);
  667. enabled = false;
  668. return AZ::RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  669. });
  670. }
  671. }
  672. }
  673. }