RayTracingFeatureProcessor.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  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 <RayTracing/RayTracingPass.h>
  10. #include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
  11. #include <Atom/RHI/Factory.h>
  12. #include <Atom/RHI/RayTracingAccelerationStructure.h>
  13. #include <Atom/RHI/RHISystemInterface.h>
  14. #include <Atom/RPI.Public/Scene.h>
  15. #include <Atom/RPI.Public/Pass/PassFilter.h>
  16. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  17. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  18. #include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h>
  19. #include <CoreLights/DirectionalLightFeatureProcessor.h>
  20. #include <CoreLights/SimplePointLightFeatureProcessor.h>
  21. #include <CoreLights/SimpleSpotLightFeatureProcessor.h>
  22. #include <CoreLights/PointLightFeatureProcessor.h>
  23. #include <CoreLights/DiskLightFeatureProcessor.h>
  24. #include <CoreLights/CapsuleLightFeatureProcessor.h>
  25. #include <CoreLights/QuadLightFeatureProcessor.h>
  26. namespace AZ
  27. {
  28. namespace Render
  29. {
  30. void RayTracingFeatureProcessor::Reflect(ReflectContext* context)
  31. {
  32. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  33. {
  34. serializeContext
  35. ->Class<RayTracingFeatureProcessor, FeatureProcessor>()
  36. ->Version(1);
  37. }
  38. }
  39. void RayTracingFeatureProcessor::Activate()
  40. {
  41. auto deviceMask{RHI::RHISystemInterface::Get()->GetRayTracingSupport()};
  42. m_rayTracingEnabled = (deviceMask != RHI::MultiDevice::NoDevices);
  43. if (!m_rayTracingEnabled)
  44. {
  45. return;
  46. }
  47. m_transformServiceFeatureProcessor = GetParentScene()->GetFeatureProcessor<TransformServiceFeatureProcessor>();
  48. // initialize the ray tracing buffer pools
  49. m_bufferPools = aznew RHI::RayTracingBufferPools;
  50. m_bufferPools->Init(deviceMask);
  51. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  52. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  53. {
  54. if ((AZStd::to_underlying(deviceMask) >> deviceIndex) & 1)
  55. {
  56. m_meshBufferIndices[deviceIndex] = {};
  57. m_materialTextureIndices[deviceIndex] = {};
  58. m_meshInfos[deviceIndex] = {};
  59. m_materialInfos[deviceIndex] = {};
  60. m_proceduralGeometryMaterialInfos[deviceIndex] = {};
  61. }
  62. }
  63. // create TLAS attachmentId
  64. AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
  65. m_tlasAttachmentId = RHI::AttachmentId(AZStd::string::format("RayTracingTlasAttachmentId_%s", uuidString.c_str()));
  66. // create the TLAS object
  67. m_tlas = aznew RHI::RayTracingTlas;
  68. // load the RayTracingSrg asset asset
  69. m_rayTracingSrgAsset = RPI::AssetUtils::LoadCriticalAsset<RPI::ShaderAsset>("shaderlib/atom/features/rayTracing/raytracingsrgs.azshader");
  70. if (!m_rayTracingSrgAsset.IsReady())
  71. {
  72. AZ_Assert(false, "Failed to load RayTracingSrg asset");
  73. return;
  74. }
  75. // create the RayTracingSceneSrg
  76. m_rayTracingSceneSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingSceneSrg"));
  77. AZ_Assert(m_rayTracingSceneSrg, "Failed to create RayTracingSceneSrg");
  78. // create the RayTracingMaterialSrg
  79. const AZ::Name rayTracingMaterialSrgName("RayTracingMaterialSrg");
  80. m_rayTracingMaterialSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingMaterialSrg"));
  81. AZ_Assert(m_rayTracingMaterialSrg, "Failed to create RayTracingMaterialSrg");
  82. EnableSceneNotification();
  83. }
  84. void RayTracingFeatureProcessor::Deactivate()
  85. {
  86. DisableSceneNotification();
  87. }
  88. RayTracingFeatureProcessor::ProceduralGeometryTypeHandle RayTracingFeatureProcessor::RegisterProceduralGeometryType(
  89. const AZStd::string& name,
  90. const Data::Instance<RPI::Shader>& intersectionShader,
  91. const AZStd::string& intersectionShaderName,
  92. const AZStd::unordered_map<int, uint32_t>& bindlessBufferIndices)
  93. {
  94. ProceduralGeometryTypeHandle geometryTypeHandle;
  95. {
  96. ProceduralGeometryType proceduralGeometryType;
  97. proceduralGeometryType.m_name = AZ::Name(name);
  98. proceduralGeometryType.m_intersectionShader = intersectionShader;
  99. proceduralGeometryType.m_intersectionShaderName = AZ::Name(intersectionShaderName);
  100. proceduralGeometryType.m_bindlessBufferIndices = bindlessBufferIndices;
  101. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  102. geometryTypeHandle = m_proceduralGeometryTypes.insert(proceduralGeometryType);
  103. }
  104. m_proceduralGeometryTypeRevision++;
  105. return geometryTypeHandle;
  106. }
  107. void RayTracingFeatureProcessor::SetProceduralGeometryTypeBindlessBufferIndex(
  108. ProceduralGeometryTypeWeakHandle geometryTypeHandle, const AZStd::unordered_map<int, uint32_t>& bindlessBufferIndices)
  109. {
  110. if (!m_rayTracingEnabled)
  111. {
  112. return;
  113. }
  114. geometryTypeHandle->m_bindlessBufferIndices = bindlessBufferIndices;
  115. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  116. }
  117. void RayTracingFeatureProcessor::AddProceduralGeometry(
  118. ProceduralGeometryTypeWeakHandle geometryTypeHandle,
  119. const Uuid& uuid,
  120. const Aabb& aabb,
  121. const SubMeshMaterial& material,
  122. RHI::RayTracingAccelerationStructureInstanceInclusionMask instanceMask,
  123. uint32_t localInstanceIndex)
  124. {
  125. if (!m_rayTracingEnabled)
  126. {
  127. return;
  128. }
  129. RHI::Ptr<AZ::RHI::RayTracingBlas> rayTracingBlas = aznew AZ::RHI::RayTracingBlas;
  130. RHI::RayTracingBlasDescriptor blasDescriptor;
  131. blasDescriptor.Build()
  132. ->AABB(aabb)
  133. ;
  134. rayTracingBlas->CreateBuffers(RHI::MultiDevice::AllDevices, &blasDescriptor, *m_bufferPools);
  135. ProceduralGeometry proceduralGeometry;
  136. proceduralGeometry.m_uuid = uuid;
  137. proceduralGeometry.m_typeHandle = geometryTypeHandle;
  138. proceduralGeometry.m_aabb = aabb;
  139. proceduralGeometry.m_instanceMask = static_cast<uint32_t>(instanceMask);
  140. proceduralGeometry.m_blas = rayTracingBlas;
  141. proceduralGeometry.m_localInstanceIndex = localInstanceIndex;
  142. MeshBlasInstance meshBlasInstance;
  143. meshBlasInstance.m_count = 1;
  144. meshBlasInstance.m_subMeshes.push_back(SubMeshBlasInstance{ rayTracingBlas });
  145. MaterialInfo materialInfo;
  146. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  147. m_proceduralGeometryLookup.emplace(uuid, m_proceduralGeometry.size());
  148. m_proceduralGeometry.push_back(proceduralGeometry);
  149. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  150. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  151. {
  152. m_proceduralGeometryMaterialInfos[deviceIndex].emplace_back();
  153. ConvertMaterial(m_proceduralGeometryMaterialInfos[deviceIndex].back(), material, deviceIndex);
  154. }
  155. m_blasInstanceMap.emplace(Data::AssetId(uuid), meshBlasInstance);
  156. geometryTypeHandle->m_instanceCount++;
  157. m_revision++;
  158. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  159. m_materialInfoBufferNeedsUpdate = true;
  160. m_indexListNeedsUpdate = true;
  161. }
  162. void RayTracingFeatureProcessor::SetProceduralGeometryTransform(
  163. const Uuid& uuid, const Transform& transform, const Vector3& nonUniformScale)
  164. {
  165. if (!m_rayTracingEnabled)
  166. {
  167. return;
  168. }
  169. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  170. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  171. {
  172. m_proceduralGeometry[it->second].m_transform = transform;
  173. m_proceduralGeometry[it->second].m_nonUniformScale = nonUniformScale;
  174. }
  175. m_revision++;
  176. }
  177. void RayTracingFeatureProcessor::SetProceduralGeometryLocalInstanceIndex(const Uuid& uuid, uint32_t localInstanceIndex)
  178. {
  179. if (!m_rayTracingEnabled)
  180. {
  181. return;
  182. }
  183. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  184. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  185. {
  186. m_proceduralGeometry[it->second].m_localInstanceIndex = localInstanceIndex;
  187. }
  188. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  189. }
  190. void RayTracingFeatureProcessor::SetProceduralGeometryMaterial(
  191. const Uuid& uuid, const RayTracingFeatureProcessor::SubMeshMaterial& material)
  192. {
  193. if (!m_rayTracingEnabled)
  194. {
  195. return;
  196. }
  197. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  198. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  199. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  200. {
  201. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  202. {
  203. ConvertMaterial(m_proceduralGeometryMaterialInfos[deviceIndex][it->second], material, deviceIndex);
  204. }
  205. }
  206. m_materialInfoBufferNeedsUpdate = true;
  207. }
  208. void RayTracingFeatureProcessor::RemoveProceduralGeometry(const Uuid& uuid)
  209. {
  210. if (!m_rayTracingEnabled)
  211. {
  212. return;
  213. }
  214. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  215. size_t materialInfoIndex = m_proceduralGeometryLookup[uuid];
  216. m_proceduralGeometry[materialInfoIndex].m_typeHandle->m_instanceCount--;
  217. if (materialInfoIndex < m_proceduralGeometry.size() - 1)
  218. {
  219. m_proceduralGeometryLookup[m_proceduralGeometry.back().m_uuid] = m_proceduralGeometryLookup[uuid];
  220. m_proceduralGeometry[materialInfoIndex] = m_proceduralGeometry.back();
  221. for (auto& [deviceIndex, materialInfos] : m_proceduralGeometryMaterialInfos)
  222. {
  223. materialInfos[materialInfoIndex] = materialInfos.back();
  224. }
  225. }
  226. m_proceduralGeometry.pop_back();
  227. for (auto& [deviceIndex, materialInfos] : m_proceduralGeometryMaterialInfos)
  228. {
  229. materialInfos.pop_back();
  230. }
  231. m_blasInstanceMap.erase(uuid);
  232. m_proceduralGeometryLookup.erase(uuid);
  233. m_revision++;
  234. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  235. m_materialInfoBufferNeedsUpdate = true;
  236. m_indexListNeedsUpdate = true;
  237. }
  238. int RayTracingFeatureProcessor::GetProceduralGeometryCount(ProceduralGeometryTypeWeakHandle geometryTypeHandle) const
  239. {
  240. return geometryTypeHandle->m_instanceCount;
  241. }
  242. void RayTracingFeatureProcessor::AddMesh(const AZ::Uuid& uuid, const Mesh& rayTracingMesh, const SubMeshVector& subMeshes)
  243. {
  244. if (!m_rayTracingEnabled)
  245. {
  246. return;
  247. }
  248. // lock the mutex to protect the mesh and BLAS lists
  249. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  250. // check to see if we already have this mesh
  251. MeshMap::iterator itMesh = m_meshes.find(uuid);
  252. if (itMesh != m_meshes.end())
  253. {
  254. AZ_Assert(false, "AddMesh called on an existing Mesh, call RemoveMesh first");
  255. return;
  256. }
  257. // add the mesh
  258. m_meshes.insert(AZStd::make_pair(uuid, rayTracingMesh));
  259. Mesh& mesh = m_meshes[uuid];
  260. // add the subMeshes to the end of the global subMesh vector
  261. // Note 1: the MeshInfo and MaterialInfo vectors are parallel with the subMesh vector
  262. // Note 2: the list of indices for the subMeshes in the global vector are stored in the parent Mesh
  263. IndexVector subMeshIndices;
  264. uint32_t subMeshGlobalIndex = aznumeric_cast<uint32_t>(m_subMeshes.size());
  265. for (uint32_t subMeshIndex = 0; subMeshIndex < subMeshes.size(); ++subMeshIndex, ++subMeshGlobalIndex)
  266. {
  267. SubMesh& subMesh = m_subMeshes.emplace_back(subMeshes[subMeshIndex]);
  268. subMesh.m_mesh = &mesh;
  269. subMesh.m_subMeshIndex = subMeshIndex;
  270. subMesh.m_globalIndex = subMeshGlobalIndex;
  271. // add to the list of global subMeshIndices, which will be stored in the Mesh
  272. subMeshIndices.push_back(subMeshGlobalIndex);
  273. // add MeshInfo and MaterialInfo entries
  274. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  275. {
  276. meshInfos.emplace_back();
  277. }
  278. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  279. {
  280. materialInfos.emplace_back();
  281. }
  282. }
  283. mesh.m_subMeshIndices = subMeshIndices;
  284. // search for an existing BLAS instance entry for this mesh using the assetId
  285. BlasInstanceMap::iterator itMeshBlasInstance = m_blasInstanceMap.find(mesh.m_assetId);
  286. if (itMeshBlasInstance == m_blasInstanceMap.end())
  287. {
  288. // make a new BLAS map entry for this mesh
  289. MeshBlasInstance meshBlasInstance;
  290. meshBlasInstance.m_count = 1;
  291. meshBlasInstance.m_subMeshes.reserve(mesh.m_subMeshIndices.size());
  292. meshBlasInstance.m_isSkinnedMesh = mesh.m_isSkinnedMesh;
  293. itMeshBlasInstance = m_blasInstanceMap.insert({ mesh.m_assetId, meshBlasInstance }).first;
  294. if (mesh.m_isSkinnedMesh)
  295. {
  296. ++m_skinnedMeshCount;
  297. }
  298. }
  299. else
  300. {
  301. itMeshBlasInstance->second.m_count++;
  302. }
  303. // create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created.
  304. // 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)
  305. // Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass
  306. // Note: the build flags are set to be the same for each BLAS created for the mesh
  307. RHI::RayTracingAccelerationStructureBuildFlags buildFlags = CreateRayTracingAccelerationStructureBuildFlags(mesh.m_isSkinnedMesh);
  308. [[maybe_unused]] bool blasInstanceFound = false;
  309. for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshIndices.size(); ++subMeshIndex)
  310. {
  311. SubMesh& subMesh = m_subMeshes[mesh.m_subMeshIndices[subMeshIndex]];
  312. RHI::RayTracingBlasDescriptor blasDescriptor;
  313. blasDescriptor.Build()
  314. ->Geometry()
  315. ->VertexFormat(subMesh.m_positionFormat)
  316. ->VertexBuffer(subMesh.m_positionVertexBufferView)
  317. ->IndexBuffer(subMesh.m_indexBufferView)
  318. ->BuildFlags(buildFlags)
  319. ;
  320. // determine if we have an existing BLAS object for this subMesh
  321. if (itMeshBlasInstance->second.m_subMeshes.size() >= subMeshIndex + 1)
  322. {
  323. // re-use existing BLAS
  324. subMesh.m_blas = itMeshBlasInstance->second.m_subMeshes[subMeshIndex].m_blas;
  325. // keep track of the fact that we re-used a BLAS
  326. blasInstanceFound = true;
  327. }
  328. else
  329. {
  330. AZ_Assert(blasInstanceFound == false, "Partial set of RayTracingBlas objects found for mesh");
  331. // create the BLAS object and store it in the BLAS list
  332. RHI::Ptr<RHI::RayTracingBlas> rayTracingBlas = aznew RHI::RayTracingBlas;
  333. itMeshBlasInstance->second.m_subMeshes.push_back({ rayTracingBlas });
  334. // create the buffers from the BLAS descriptor
  335. rayTracingBlas->CreateBuffers(RHI::RHISystemInterface::Get()->GetRayTracingSupport(), &blasDescriptor, *m_bufferPools);
  336. // store the BLAS in the mesh
  337. subMesh.m_blas = rayTracingBlas;
  338. }
  339. }
  340. AZ::Transform noScaleTransform = mesh.m_transform;
  341. noScaleTransform.ExtractUniformScale();
  342. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  343. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  344. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  345. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  346. // store the mesh buffers and material textures in the resource lists
  347. for (uint32_t subMeshIndex : mesh.m_subMeshIndices)
  348. {
  349. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  350. AZ_Assert(subMesh.m_indexShaderBufferView.get(), "RayTracing Mesh IndexBuffer cannot be null");
  351. AZ_Assert(subMesh.m_positionShaderBufferView.get(), "RayTracing Mesh PositionBuffer cannot be null");
  352. AZ_Assert(subMesh.m_normalShaderBufferView.get(), "RayTracing Mesh NormalBuffer cannot be null");
  353. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  354. {
  355. MeshInfo& meshInfo = meshInfos[subMesh.m_globalIndex];
  356. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  357. meshInfo.m_bufferFlags = subMesh.m_bufferFlags;
  358. meshInfo.m_indexByteOffset = subMesh.m_indexBufferView.GetByteOffset();
  359. meshInfo.m_positionByteOffset = subMesh.m_positionVertexBufferView.GetByteOffset();
  360. meshInfo.m_normalByteOffset = subMesh.m_normalVertexBufferView.GetByteOffset();
  361. meshInfo.m_tangentByteOffset =
  362. subMesh.m_tangentShaderBufferView ? subMesh.m_tangentVertexBufferView.GetByteOffset() : 0;
  363. meshInfo.m_bitangentByteOffset =
  364. subMesh.m_bitangentShaderBufferView ? subMesh.m_bitangentVertexBufferView.GetByteOffset() : 0;
  365. meshInfo.m_uvByteOffset = subMesh.m_uvShaderBufferView ? subMesh.m_uvVertexBufferView.GetByteOffset() : 0;
  366. auto& materialInfos{ m_materialInfos[deviceIndex] };
  367. MaterialInfo& materialInfo = materialInfos[subMesh.m_globalIndex];
  368. ConvertMaterial(materialInfo, subMesh.m_material, deviceIndex);
  369. auto& meshBufferIndices = m_meshBufferIndices[deviceIndex];
  370. // add mesh buffers
  371. meshInfo.m_bufferStartIndex = meshBufferIndices.AddEntry(
  372. {
  373. #if USE_BINDLESS_SRG
  374. subMesh.m_indexShaderBufferView.get() ? subMesh.m_indexShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  375. subMesh.m_positionShaderBufferView.get() ? subMesh.m_positionShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  376. subMesh.m_normalShaderBufferView.get() ? subMesh.m_normalShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  377. subMesh.m_tangentShaderBufferView.get() ? subMesh.m_tangentShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  378. subMesh.m_bitangentShaderBufferView.get() ? subMesh.m_bitangentShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  379. subMesh.m_uvShaderBufferView.get() ? subMesh.m_uvShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex
  380. #else
  381. m_meshBuffers.AddResource(subMesh.m_indexShaderBufferView.get()),
  382. m_meshBuffers.AddResource(subMesh.m_positionShaderBufferView.get()),
  383. m_meshBuffers.AddResource(subMesh.m_normalShaderBufferView.get()),
  384. m_meshBuffers.AddResource(subMesh.m_tangentShaderBufferView.get()),
  385. m_meshBuffers.AddResource(subMesh.m_bitangentShaderBufferView.get()),
  386. m_meshBuffers.AddResource(subMesh.m_uvShaderBufferView.get())
  387. #endif
  388. });
  389. // add reflection probe data
  390. if (mesh.m_reflectionProbe.m_reflectionProbeCubeMap.get())
  391. {
  392. materialInfo.m_reflectionProbeCubeMapIndex = mesh.m_reflectionProbe.m_reflectionProbeCubeMap->GetImageView()->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex();
  393. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  394. {
  395. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  396. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  397. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  398. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  399. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  400. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  401. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  402. }
  403. }
  404. }
  405. }
  406. m_revision++;
  407. m_subMeshCount += aznumeric_cast<uint32_t>(subMeshes.size());
  408. m_meshInfoBufferNeedsUpdate = true;
  409. m_materialInfoBufferNeedsUpdate = true;
  410. m_indexListNeedsUpdate = true;
  411. }
  412. void RayTracingFeatureProcessor::RemoveMesh(const AZ::Uuid& uuid)
  413. {
  414. if (!m_rayTracingEnabled)
  415. {
  416. return;
  417. }
  418. // lock the mutex to protect the mesh and BLAS lists
  419. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  420. MeshMap::iterator itMesh = m_meshes.find(uuid);
  421. if (itMesh != m_meshes.end())
  422. {
  423. Mesh& mesh = itMesh->second;
  424. // decrement the count from the BLAS instances, and check to see if we can remove them
  425. BlasInstanceMap::iterator itBlas = m_blasInstanceMap.find(mesh.m_assetId);
  426. if (itBlas != m_blasInstanceMap.end())
  427. {
  428. itBlas->second.m_count--;
  429. if (itBlas->second.m_count == 0)
  430. {
  431. if (itBlas->second.m_isSkinnedMesh)
  432. {
  433. --m_skinnedMeshCount;
  434. }
  435. m_blasInstanceMap.erase(itBlas);
  436. }
  437. }
  438. // remove the SubMeshes
  439. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  440. {
  441. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  442. uint32_t globalIndex = subMesh.m_globalIndex;
  443. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  444. {
  445. MeshInfo& meshInfo = meshInfos[globalIndex];
  446. auto& meshBufferIndices = m_meshBufferIndices[deviceIndex];
  447. meshBufferIndices.RemoveEntry(meshInfo.m_bufferStartIndex);
  448. }
  449. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  450. {
  451. MaterialInfo& materialInfo = m_materialInfos[deviceIndex][globalIndex];
  452. materialTextureIndices.RemoveEntry(materialInfo.m_textureStartIndex);
  453. }
  454. #if !USE_BINDLESS_SRG
  455. m_meshBuffers.RemoveResource(subMesh.m_indexShaderBufferView.get());
  456. m_meshBuffers.RemoveResource(subMesh.m_positionShaderBufferView.get());
  457. m_meshBuffers.RemoveResource(subMesh.m_normalShaderBufferView.get());
  458. m_meshBuffers.RemoveResource(subMesh.m_tangentShaderBufferView.get());
  459. m_meshBuffers.RemoveResource(subMesh.m_bitangentShaderBufferView.get());
  460. m_meshBuffers.RemoveResource(subMesh.m_uvShaderBufferView.get());
  461. m_materialTextures.RemoveResource(subMesh.m_baseColorImageView.get());
  462. m_materialTextures.RemoveResource(subMesh.m_normalImageView.get());
  463. m_materialTextures.RemoveResource(subMesh.m_metallicImageView.get());
  464. m_materialTextures.RemoveResource(subMesh.m_roughnessImageView.get());
  465. m_materialTextures.RemoveResource(subMesh.m_emissiveImageView.get());
  466. #endif
  467. if (globalIndex < m_subMeshes.size() - 1)
  468. {
  469. // 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
  470. m_subMeshes[globalIndex] = m_subMeshes.back();
  471. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  472. {
  473. auto& materialInfos{ m_materialInfos[deviceIndex] };
  474. meshInfos[globalIndex] = meshInfos.back();
  475. materialInfos[globalIndex] = materialInfos.back();
  476. }
  477. // update the global index for the swapped subMesh
  478. m_subMeshes[globalIndex].m_globalIndex = globalIndex;
  479. // update the global index in the parent Mesh' subMesh list
  480. Mesh* swappedSubMeshParent = m_subMeshes[globalIndex].m_mesh;
  481. uint32_t swappedSubMeshIndex = m_subMeshes[globalIndex].m_subMeshIndex;
  482. swappedSubMeshParent->m_subMeshIndices[swappedSubMeshIndex] = globalIndex;
  483. }
  484. m_subMeshes.pop_back();
  485. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  486. {
  487. auto& materialInfos{ m_materialInfos[deviceIndex] };
  488. meshInfos.pop_back();
  489. materialInfos.pop_back();
  490. }
  491. }
  492. // remove from the Mesh list
  493. m_subMeshCount -= aznumeric_cast<uint32_t>(mesh.m_subMeshIndices.size());
  494. m_meshes.erase(itMesh);
  495. m_revision++;
  496. // reset all data structures if all meshes were removed (i.e., empty scene)
  497. if (m_subMeshCount == 0)
  498. {
  499. m_meshes.clear();
  500. m_subMeshes.clear();
  501. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  502. {
  503. meshInfos.clear();
  504. }
  505. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  506. {
  507. materialInfos.clear();
  508. }
  509. for (auto& [deviceIndex, meshBufferIndices] : m_meshBufferIndices)
  510. {
  511. meshBufferIndices.Reset();
  512. }
  513. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  514. {
  515. materialTextureIndices.Reset();
  516. }
  517. #if !USE_BINDLESS_SRG
  518. m_meshBuffers.Reset();
  519. m_materialTextures.Reset();
  520. #endif
  521. }
  522. }
  523. m_meshInfoBufferNeedsUpdate = true;
  524. m_materialInfoBufferNeedsUpdate = true;
  525. m_indexListNeedsUpdate = true;
  526. }
  527. void RayTracingFeatureProcessor::SetMeshTransform(const AZ::Uuid& uuid, const AZ::Transform transform, const AZ::Vector3 nonUniformScale)
  528. {
  529. if (!m_rayTracingEnabled)
  530. {
  531. return;
  532. }
  533. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  534. MeshMap::iterator itMesh = m_meshes.find(uuid);
  535. if (itMesh != m_meshes.end())
  536. {
  537. Mesh& mesh = itMesh->second;
  538. mesh.m_transform = transform;
  539. mesh.m_nonUniformScale = nonUniformScale;
  540. m_revision++;
  541. // create a world inverse transpose 3x4 matrix
  542. AZ::Transform noScaleTransform = mesh.m_transform;
  543. noScaleTransform.ExtractUniformScale();
  544. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  545. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  546. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  547. // update all MeshInfos for this Mesh with the new transform
  548. for (const auto& subMeshIndex : mesh.m_subMeshIndices)
  549. {
  550. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  551. {
  552. MeshInfo& meshInfo = meshInfos[subMeshIndex];
  553. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  554. }
  555. }
  556. m_meshInfoBufferNeedsUpdate = true;
  557. }
  558. }
  559. void RayTracingFeatureProcessor::SetMeshReflectionProbe(const AZ::Uuid& uuid, const Mesh::ReflectionProbe& reflectionProbe)
  560. {
  561. if (!m_rayTracingEnabled)
  562. {
  563. return;
  564. }
  565. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  566. MeshMap::iterator itMesh = m_meshes.find(uuid);
  567. if (itMesh != m_meshes.end())
  568. {
  569. Mesh& mesh = itMesh->second;
  570. // update the Mesh reflection probe data
  571. mesh.m_reflectionProbe = reflectionProbe;
  572. // update all of the subMeshes
  573. const Data::Instance<RPI::Image>& reflectionProbeCubeMap = reflectionProbe.m_reflectionProbeCubeMap;
  574. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  575. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  576. {
  577. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  578. uint32_t globalIndex = subMesh.m_globalIndex;
  579. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  580. {
  581. MaterialInfo& materialInfo = materialInfos[globalIndex];
  582. materialInfo.m_reflectionProbeCubeMapIndex = reflectionProbeCubeMap.get()
  583. ? reflectionProbeCubeMap->GetImageView()->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex()
  584. : InvalidIndex;
  585. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  586. {
  587. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  588. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  589. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  590. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  591. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  592. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  593. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  594. }
  595. else
  596. {
  597. materialInfo.m_reflectionProbeData.m_useReflectionProbe = false;
  598. }
  599. }
  600. }
  601. m_materialInfoBufferNeedsUpdate = true;
  602. }
  603. }
  604. void RayTracingFeatureProcessor::SetMeshMaterials(const AZ::Uuid& uuid, const SubMeshMaterialVector& subMeshMaterials)
  605. {
  606. if (!m_rayTracingEnabled)
  607. {
  608. return;
  609. }
  610. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  611. MeshMap::iterator itMesh = m_meshes.find(uuid);
  612. if (itMesh != m_meshes.end())
  613. {
  614. Mesh& mesh = itMesh->second;
  615. AZ_Assert(
  616. subMeshMaterials.size() == mesh.m_subMeshIndices.size(),
  617. "The size of subMeshes in SetMeshMaterial must be the same as in AddMesh");
  618. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  619. {
  620. const SubMesh& subMesh = m_subMeshes[subMeshIndex];
  621. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  622. {
  623. ConvertMaterial(materialInfos[subMesh.m_globalIndex], subMeshMaterials[subMesh.m_subMeshIndex], deviceIndex);
  624. }
  625. }
  626. m_materialInfoBufferNeedsUpdate = true;
  627. m_indexListNeedsUpdate = true;
  628. }
  629. }
  630. uint32_t RayTracingFeatureProcessor::BeginFrame()
  631. {
  632. if (m_tlasRevision != m_revision)
  633. {
  634. m_tlasRevision = m_revision;
  635. // create the TLAS descriptor
  636. RHI::RayTracingTlasDescriptor tlasDescriptor;
  637. RHI::RayTracingTlasDescriptor* tlasDescriptorBuild = tlasDescriptor.Build();
  638. uint32_t instanceIndex = 0;
  639. for (auto& subMesh : m_subMeshes)
  640. {
  641. tlasDescriptorBuild->Instance()
  642. ->InstanceID(instanceIndex)
  643. ->InstanceMask(subMesh.m_mesh->m_instanceMask)
  644. ->HitGroupIndex(0)
  645. ->Blas(subMesh.m_blas)
  646. ->Transform(subMesh.m_mesh->m_transform)
  647. ->NonUniformScale(subMesh.m_mesh->m_nonUniformScale)
  648. ->Transparent(subMesh.m_material.m_irradianceColor.GetA() < 1.0f);
  649. instanceIndex++;
  650. }
  651. unsigned proceduralHitGroupIndex = 1; // Hit group 0 is used for normal meshes
  652. AZStd::unordered_map<Name, unsigned> geometryTypeMap;
  653. geometryTypeMap.reserve(m_proceduralGeometryTypes.size());
  654. for (auto it = m_proceduralGeometryTypes.cbegin(); it != m_proceduralGeometryTypes.cend(); ++it)
  655. {
  656. geometryTypeMap[it->m_name] = proceduralHitGroupIndex++;
  657. }
  658. for (const auto& proceduralGeometry : m_proceduralGeometry)
  659. {
  660. tlasDescriptorBuild->Instance()
  661. ->InstanceID(instanceIndex)
  662. ->InstanceMask(proceduralGeometry.m_instanceMask)
  663. ->HitGroupIndex(geometryTypeMap[proceduralGeometry.m_typeHandle->m_name])
  664. ->Blas(proceduralGeometry.m_blas)
  665. ->Transform(proceduralGeometry.m_transform)
  666. ->NonUniformScale(proceduralGeometry.m_nonUniformScale);
  667. instanceIndex++;
  668. }
  669. // create the TLAS buffers based on the descriptor
  670. RHI::Ptr<RHI::RayTracingTlas>& rayTracingTlas = m_tlas;
  671. rayTracingTlas->CreateBuffers(RHI::RHISystemInterface::Get()->GetRayTracingSupport(), &tlasDescriptor, *m_bufferPools);
  672. }
  673. // update and compile the RayTracingSceneSrg and RayTracingMaterialSrg
  674. // Note: the timing of this update is very important, it needs to be updated after the TLAS is allocated so it can
  675. // be set on the RayTracingSceneSrg for this frame, and the ray tracing mesh data in the RayTracingSceneSrg must
  676. // exactly match the TLAS. Any mismatch in this data may result in a TDR.
  677. UpdateRayTracingSrgs();
  678. return m_revision;
  679. }
  680. void RayTracingFeatureProcessor::UpdateRayTracingSrgs()
  681. {
  682. AZ_PROFILE_SCOPE(AzRender, "RayTracingFeatureProcessor::UpdateRayTracingSrgs");
  683. if (!m_tlas->GetTlasBuffer())
  684. {
  685. return;
  686. }
  687. if (m_rayTracingSceneSrg->IsQueuedForCompile() || m_rayTracingMaterialSrg->IsQueuedForCompile())
  688. {
  689. //[GFX TODO][ATOM-14792] AtomSampleViewer: Reset scene and feature processors before switching to sample
  690. return;
  691. }
  692. // lock the mutex to protect the mesh and BLAS lists
  693. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  694. if (HasMeshGeometry())
  695. {
  696. UpdateMeshInfoBuffer();
  697. }
  698. if (HasProceduralGeometry())
  699. {
  700. UpdateProceduralGeometryInfoBuffer();
  701. }
  702. if (HasGeometry())
  703. {
  704. UpdateMaterialInfoBuffer();
  705. UpdateIndexLists();
  706. }
  707. UpdateRayTracingSceneSrg();
  708. UpdateRayTracingMaterialSrg();
  709. }
  710. void RayTracingFeatureProcessor::UpdateMeshInfoBuffer()
  711. {
  712. if (m_meshInfoBufferNeedsUpdate)
  713. {
  714. AZStd::unordered_map<int, const void*> rawMeshInfos;
  715. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  716. {
  717. rawMeshInfos[deviceIndex] = meshInfos.data();
  718. }
  719. size_t meshInfoByteCount = m_meshInfos.begin()->second.size() * sizeof(MeshInfo);
  720. m_meshInfoGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMeshInfos, meshInfoByteCount);
  721. m_meshInfoBufferNeedsUpdate = false;
  722. }
  723. }
  724. void RayTracingFeatureProcessor::UpdateProceduralGeometryInfoBuffer()
  725. {
  726. if (!m_proceduralGeometryInfoBufferNeedsUpdate)
  727. {
  728. return;
  729. }
  730. AZStd::unordered_map<int, AZStd::vector<uint32_t>> proceduralGeometryInfos;
  731. for (const auto& proceduralGeometry : m_proceduralGeometry)
  732. {
  733. for (auto& [deviceIndex, bindlessBufferIndex] : proceduralGeometry.m_typeHandle->m_bindlessBufferIndices)
  734. {
  735. auto& proceduralGeometryInfo = proceduralGeometryInfos[deviceIndex];
  736. if (proceduralGeometryInfo.empty())
  737. {
  738. proceduralGeometryInfo.reserve(m_proceduralGeometry.size() * 2);
  739. }
  740. proceduralGeometryInfo.push_back(bindlessBufferIndex);
  741. proceduralGeometryInfo.push_back(proceduralGeometry.m_localInstanceIndex);
  742. }
  743. }
  744. AZStd::unordered_map<int, const void*> rawProceduralGeometryInfos;
  745. for (auto& [deviceIndex, proceduralGeometryInfo] : proceduralGeometryInfos)
  746. {
  747. rawProceduralGeometryInfos[deviceIndex] = proceduralGeometryInfo.data();
  748. }
  749. m_proceduralGeometryInfoGpuBuffer.AdvanceCurrentBufferAndUpdateData(
  750. rawProceduralGeometryInfos, m_proceduralGeometry.size() * 2 * sizeof(uint32_t));
  751. m_proceduralGeometryInfoBufferNeedsUpdate = false;
  752. }
  753. void RayTracingFeatureProcessor::UpdateMaterialInfoBuffer()
  754. {
  755. if (m_materialInfoBufferNeedsUpdate)
  756. {
  757. m_materialInfoGpuBuffer.AdvanceCurrentElement();
  758. m_materialInfoGpuBuffer.CreateOrResizeCurrentBufferWithElementCount<MaterialInfo>(
  759. m_subMeshCount + m_proceduralGeometryMaterialInfos.begin()->second.size());
  760. m_materialInfoGpuBuffer.UpdateCurrentBufferData(m_materialInfos);
  761. m_materialInfoGpuBuffer.UpdateCurrentBufferData(m_proceduralGeometryMaterialInfos, m_subMeshCount);
  762. m_materialInfoBufferNeedsUpdate = false;
  763. }
  764. }
  765. void RayTracingFeatureProcessor::UpdateIndexLists()
  766. {
  767. if (m_indexListNeedsUpdate)
  768. {
  769. #if !USE_BINDLESS_SRG
  770. // resolve to the true indices using the indirection list
  771. // Note: this is done on the CPU to avoid double-indirection in the shader
  772. IndexVector resolvedMeshBufferIndices(m_meshBufferIndices.GetIndexList().size());
  773. uint32_t resolvedMeshBufferIndex = 0;
  774. for (auto& meshBufferIndex : m_meshBufferIndices.GetIndexList())
  775. {
  776. if (!m_meshBufferIndices.IsValidIndex(meshBufferIndex))
  777. {
  778. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = InvalidIndex;
  779. }
  780. else
  781. {
  782. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = m_meshBuffers.GetIndirectionList()[meshBufferIndex];
  783. }
  784. }
  785. m_meshBufferIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(resolvedMeshBufferIndices);
  786. #else
  787. AZStd::unordered_map<int, const void*> rawMeshData;
  788. for (auto& [deviceIndex, meshBufferIndices] : m_meshBufferIndices)
  789. {
  790. rawMeshData[deviceIndex] = meshBufferIndices.GetIndexList().data();
  791. }
  792. size_t newMeshBufferIndicesByteCount = m_meshBufferIndices.begin()->second.GetIndexList().size() * sizeof(uint32_t);
  793. m_meshBufferIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMeshData, newMeshBufferIndicesByteCount);
  794. #endif
  795. #if !USE_BINDLESS_SRG
  796. // resolve to the true indices using the indirection list
  797. // Note: this is done on the CPU to avoid double-indirection in the shader
  798. IndexVector resolvedMaterialTextureIndices(m_materialTextureIndices.GetIndexList().size());
  799. uint32_t resolvedMaterialTextureIndex = 0;
  800. for (auto& materialTextureIndex : m_materialTextureIndices.GetIndexList())
  801. {
  802. if (!m_materialTextureIndices.IsValidIndex(materialTextureIndex))
  803. {
  804. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = InvalidIndex;
  805. }
  806. else
  807. {
  808. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = m_materialTextures.GetIndirectionList()[materialTextureIndex];
  809. }
  810. }
  811. m_materialTextureIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(resolvedMaterialTextureIndices);
  812. #else
  813. AZStd::unordered_map<int, const void*> rawMaterialData;
  814. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  815. {
  816. rawMaterialData[deviceIndex] = materialTextureIndices.GetIndexList().data();
  817. }
  818. size_t newMaterialTextureIndicesByteCount = m_materialTextureIndices.begin()->second.GetIndexList().size() * sizeof(uint32_t);
  819. m_materialTextureIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMaterialData, newMaterialTextureIndicesByteCount);
  820. #endif
  821. m_indexListNeedsUpdate = false;
  822. }
  823. }
  824. void RayTracingFeatureProcessor::UpdateRayTracingSceneSrg()
  825. {
  826. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingSceneSrg->GetLayout();
  827. RHI::ShaderInputImageIndex imageIndex;
  828. RHI::ShaderInputBufferIndex bufferIndex;
  829. RHI::ShaderInputConstantIndex constantIndex;
  830. // TLAS
  831. uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(m_tlas->GetTlasBuffer()->GetDescriptor().m_byteCount);
  832. RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(tlasBufferByteCount);
  833. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_scene"));
  834. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_tlas->GetTlasBuffer()->BuildBufferView(bufferViewDescriptor).get());
  835. // directional lights
  836. const auto directionalLightFP = GetParentScene()->GetFeatureProcessor<DirectionalLightFeatureProcessor>();
  837. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_directionalLights"));
  838. m_rayTracingSceneSrg->SetBufferView(
  839. bufferIndex,
  840. directionalLightFP->GetLightBuffer()->GetBufferView());
  841. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_directionalLightCount"));
  842. m_rayTracingSceneSrg->SetConstant(constantIndex, directionalLightFP->GetLightCount());
  843. // simple point lights
  844. const auto simplePointLightFP = GetParentScene()->GetFeatureProcessor<SimplePointLightFeatureProcessor>();
  845. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simplePointLights"));
  846. m_rayTracingSceneSrg->SetBufferView(
  847. bufferIndex,
  848. simplePointLightFP->GetLightBuffer()->GetBufferView());
  849. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simplePointLightCount"));
  850. m_rayTracingSceneSrg->SetConstant(constantIndex, simplePointLightFP->GetLightCount());
  851. // simple spot lights
  852. const auto simpleSpotLightFP = GetParentScene()->GetFeatureProcessor<SimpleSpotLightFeatureProcessor>();
  853. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simpleSpotLights"));
  854. m_rayTracingSceneSrg->SetBufferView(
  855. bufferIndex,
  856. simpleSpotLightFP->GetLightBuffer()->GetBufferView());
  857. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simpleSpotLightCount"));
  858. m_rayTracingSceneSrg->SetConstant(constantIndex, simpleSpotLightFP->GetLightCount());
  859. // point lights (sphere)
  860. const auto pointLightFP = GetParentScene()->GetFeatureProcessor<PointLightFeatureProcessor>();
  861. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_pointLights"));
  862. m_rayTracingSceneSrg->SetBufferView(
  863. bufferIndex,
  864. pointLightFP->GetLightBuffer()->GetBufferView());
  865. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_pointLightCount"));
  866. m_rayTracingSceneSrg->SetConstant(constantIndex, pointLightFP->GetLightCount());
  867. // disk lights
  868. const auto diskLightFP = GetParentScene()->GetFeatureProcessor<DiskLightFeatureProcessor>();
  869. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_diskLights"));
  870. m_rayTracingSceneSrg->SetBufferView(
  871. bufferIndex,
  872. diskLightFP->GetLightBuffer()->GetBufferView());
  873. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_diskLightCount"));
  874. m_rayTracingSceneSrg->SetConstant(constantIndex, diskLightFP->GetLightCount());
  875. // capsule lights
  876. const auto capsuleLightFP = GetParentScene()->GetFeatureProcessor<CapsuleLightFeatureProcessor>();
  877. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_capsuleLights"));
  878. m_rayTracingSceneSrg->SetBufferView(
  879. bufferIndex,
  880. capsuleLightFP->GetLightBuffer()->GetBufferView());
  881. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_capsuleLightCount"));
  882. m_rayTracingSceneSrg->SetConstant(constantIndex, capsuleLightFP->GetLightCount());
  883. // quad lights
  884. const auto quadLightFP = GetParentScene()->GetFeatureProcessor<QuadLightFeatureProcessor>();
  885. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_quadLights"));
  886. m_rayTracingSceneSrg->SetBufferView(
  887. bufferIndex,
  888. quadLightFP->GetLightBuffer()->GetBufferView());
  889. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_quadLightCount"));
  890. m_rayTracingSceneSrg->SetConstant(constantIndex, quadLightFP->GetLightCount());
  891. // diffuse environment map for sky hits
  892. ImageBasedLightFeatureProcessor* imageBasedLightFeatureProcessor = GetParentScene()->GetFeatureProcessor<ImageBasedLightFeatureProcessor>();
  893. if (imageBasedLightFeatureProcessor)
  894. {
  895. imageIndex = srgLayout->FindShaderInputImageIndex(AZ::Name("m_diffuseEnvMap"));
  896. m_rayTracingSceneSrg->SetImage(imageIndex, imageBasedLightFeatureProcessor->GetDiffuseImage());
  897. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblOrientation"));
  898. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetOrientation());
  899. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblExposure"));
  900. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetExposure());
  901. }
  902. if (m_meshInfoGpuBuffer.IsCurrentBufferValid())
  903. {
  904. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshInfo"));
  905. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshInfoGpuBuffer.GetCurrentBufferView());
  906. }
  907. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_meshInfoCount"));
  908. m_rayTracingSceneSrg->SetConstant(constantIndex, m_subMeshCount);
  909. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshBufferIndices"));
  910. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshBufferIndicesGpuBuffer.GetCurrentBufferView());
  911. if (m_proceduralGeometryInfoGpuBuffer.IsCurrentBufferValid())
  912. {
  913. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_proceduralGeometryInfo"));
  914. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_proceduralGeometryInfoGpuBuffer.GetCurrentBufferView());
  915. }
  916. #if !USE_BINDLESS_SRG
  917. RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers"));
  918. m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, m_meshBuffers.GetResourceList());
  919. #endif
  920. m_rayTracingSceneSrg->Compile();
  921. }
  922. void RayTracingFeatureProcessor::UpdateRayTracingMaterialSrg()
  923. {
  924. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingMaterialSrg->GetLayout();
  925. RHI::ShaderInputBufferIndex bufferIndex;
  926. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialInfo"));
  927. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialInfoGpuBuffer.GetCurrentBufferView());
  928. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialTextureIndices"));
  929. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialTextureIndicesGpuBuffer.GetCurrentBufferView());
  930. #if !USE_BINDLESS_SRG
  931. RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures"));
  932. m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, m_materialTextures.GetResourceList());
  933. #endif
  934. m_rayTracingMaterialSrg->Compile();
  935. }
  936. void RayTracingFeatureProcessor::OnRenderPipelineChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline, RPI::SceneNotification::RenderPipelineChangeType changeType)
  937. {
  938. if (!m_rayTracingEnabled)
  939. {
  940. return;
  941. }
  942. // only enable the RayTracingAccelerationStructurePass for each device on the first pipeline in this scene, this will avoid
  943. // multiple updates to the same AS
  944. if (changeType == RPI::SceneNotification::RenderPipelineChangeType::Added
  945. || changeType == RPI::SceneNotification::RenderPipelineChangeType::Removed)
  946. {
  947. AZ::RPI::Pass* firstRayTracingAccelerationStructurePass{ nullptr };
  948. auto rayTracingDeviceMask{ RHI::RHISystemInterface::Get()->GetRayTracingSupport() };
  949. AZ::RHI::MultiDevice::DeviceMask devicesToAdd{ rayTracingDeviceMask };
  950. AZ::RPI::PassFilter passFilter =
  951. AZ::RPI::PassFilter::CreateWithTemplateName(AZ::Name("RayTracingAccelerationStructurePassTemplate"), GetParentScene());
  952. AZ::RPI::PassSystemInterface::Get()->ForEachPass(
  953. passFilter,
  954. [&devicesToAdd, &firstRayTracingAccelerationStructurePass, &rayTracingDeviceMask](
  955. AZ::RPI::Pass* pass) -> AZ::RPI::PassFilterExecutionFlow
  956. {
  957. if (!firstRayTracingAccelerationStructurePass)
  958. {
  959. firstRayTracingAccelerationStructurePass = pass;
  960. }
  961. // we always set an invalid device index to the first available device
  962. if (pass->GetDeviceIndex() == RHI::MultiDevice::InvalidDeviceIndex)
  963. {
  964. pass->SetDeviceIndex(az_ctz_u32(AZStd::to_underlying(rayTracingDeviceMask)));
  965. }
  966. auto mask = RHI::MultiDevice::DeviceMask(AZ_BIT(pass->GetDeviceIndex()));
  967. // only have one RayTracingAccelerationStructurePass per device
  968. pass->SetEnabled((mask & devicesToAdd) != RHI::MultiDevice::NoDevices);
  969. devicesToAdd &= ~mask;
  970. return AZ::RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  971. });
  972. // we only add the passes on the other devices if the pipeline contains one in the first place
  973. if (firstRayTracingAccelerationStructurePass)
  974. {
  975. // add passes for the remaining devices
  976. while (devicesToAdd != RHI::MultiDevice::NoDevices)
  977. {
  978. auto deviceIndex{ az_ctz_u32(AZStd::to_underlying(devicesToAdd)) };
  979. AZStd::shared_ptr<RPI::PassRequest> passRequest = AZStd::make_shared<RPI::PassRequest>();
  980. passRequest->m_templateName = Name("RayTracingAccelerationStructurePassTemplate");
  981. passRequest->m_passName = Name("RayTracingAccelerationStructurePass" + AZStd::to_string(deviceIndex));
  982. AZStd::shared_ptr<RPI::PassData> passData = AZStd::make_shared<RPI::PassData>();
  983. passData->m_deviceIndex = deviceIndex;
  984. passRequest->m_passData = passData;
  985. auto pass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(passRequest.get());
  986. renderPipeline->AddPassAfter(pass, firstRayTracingAccelerationStructurePass->GetName());
  987. devicesToAdd &= RHI::MultiDevice::DeviceMask(~AZ_BIT(deviceIndex));
  988. }
  989. }
  990. }
  991. }
  992. AZ::RHI::RayTracingAccelerationStructureBuildFlags RayTracingFeatureProcessor::CreateRayTracingAccelerationStructureBuildFlags(bool isSkinnedMesh)
  993. {
  994. AZ::RHI::RayTracingAccelerationStructureBuildFlags buildFlags;
  995. if (isSkinnedMesh)
  996. {
  997. buildFlags = AZ::RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_UPDATE | AZ::RHI::RayTracingAccelerationStructureBuildFlags::FAST_BUILD;
  998. }
  999. else
  1000. {
  1001. buildFlags = AZ::RHI::RayTracingAccelerationStructureBuildFlags::FAST_TRACE;
  1002. }
  1003. return buildFlags;
  1004. }
  1005. void RayTracingFeatureProcessor::ConvertMaterial(MaterialInfo& materialInfo, const SubMeshMaterial& subMeshMaterial, int deviceIndex)
  1006. {
  1007. subMeshMaterial.m_baseColor.StoreToFloat4(materialInfo.m_baseColor.data());
  1008. subMeshMaterial.m_emissiveColor.StoreToFloat4(materialInfo.m_emissiveColor.data());
  1009. subMeshMaterial.m_irradianceColor.StoreToFloat4(materialInfo.m_irradianceColor.data());
  1010. materialInfo.m_metallicFactor = subMeshMaterial.m_metallicFactor;
  1011. materialInfo.m_roughnessFactor = subMeshMaterial.m_roughnessFactor;
  1012. materialInfo.m_textureFlags = subMeshMaterial.m_textureFlags;
  1013. if (materialInfo.m_textureStartIndex != InvalidIndex)
  1014. {
  1015. m_materialTextureIndices[deviceIndex].RemoveEntry(materialInfo.m_textureStartIndex);
  1016. #if !USE_BINDLESS_SRG
  1017. m_materialTextures.RemoveResource(subMeshMaterial.m_baseColorImageView.get());
  1018. m_materialTextures.RemoveResource(subMeshMaterial.m_normalImageView.get());
  1019. m_materialTextures.RemoveResource(subMeshMaterial.m_metallicImageView.get());
  1020. m_materialTextures.RemoveResource(subMeshMaterial.m_roughnessImageView.get());
  1021. m_materialTextures.RemoveResource(subMeshMaterial.m_emissiveImageView.get());
  1022. #endif
  1023. }
  1024. materialInfo.m_textureStartIndex = m_materialTextureIndices[deviceIndex].AddEntry({
  1025. #if USE_BINDLESS_SRG
  1026. subMeshMaterial.m_baseColorImageView.get() ? subMeshMaterial.m_baseColorImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1027. subMeshMaterial.m_normalImageView.get() ? subMeshMaterial.m_normalImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1028. subMeshMaterial.m_metallicImageView.get() ? subMeshMaterial.m_metallicImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1029. subMeshMaterial.m_roughnessImageView.get() ? subMeshMaterial.m_roughnessImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1030. subMeshMaterial.m_emissiveImageView.get() ? subMeshMaterial.m_emissiveImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex
  1031. #else
  1032. m_materialTextures.AddResource(subMeshMaterial.m_baseColorImageView.get()),
  1033. m_materialTextures.AddResource(subMeshMaterial.m_normalImageView.get()),
  1034. m_materialTextures.AddResource(subMeshMaterial.m_metallicImageView.get()),
  1035. m_materialTextures.AddResource(subMeshMaterial.m_roughnessImageView.get()),
  1036. m_materialTextures.AddResource(subMeshMaterial.m_emissiveImageView.get())
  1037. #endif
  1038. });
  1039. }
  1040. }
  1041. }