DiffuseProbeGridFeatureProcessor.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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 <AzCore/Serialization/SerializeContext.h>
  9. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  10. #include <Atom/RPI.Public/RenderPipeline.h>
  11. #include <Atom/RPI.Public/RPIUtils.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/RPI.Public/Shader/Shader.h>
  14. #include <Atom/RPI.Public/View.h>
  15. #include <Atom/RPI.Public/Pass/PassFilter.h>
  16. #include <Render/DiffuseProbeGridFeatureProcessor.h>
  17. #include <DiffuseProbeGrid_Traits_Platform.h>
  18. #include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
  19. #include <Atom/Feature/SpecularReflections/SpecularReflectionsFeatureProcessorInterface.h>
  20. #include <Atom/RHI/Factory.h>
  21. #include <Atom/RHI/RHISystemInterface.h>
  22. #include <Atom/RHI/SingleDevicePipelineState.h>
  23. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  24. // This component invokes shaders based on Nvidia's RTX-GI SDK.
  25. // Please refer to "Shaders/DiffuseGlobalIllumination/Nvidia RTX-GI License.txt" for license information.
  26. namespace AZ
  27. {
  28. namespace Render
  29. {
  30. void DiffuseProbeGridFeatureProcessor::Reflect(ReflectContext* context)
  31. {
  32. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  33. {
  34. serializeContext
  35. ->Class<DiffuseProbeGridFeatureProcessor, FeatureProcessor>()
  36. ->Version(1);
  37. }
  38. }
  39. void DiffuseProbeGridFeatureProcessor::Activate()
  40. {
  41. if (!AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
  42. {
  43. // GI is not supported on this platform
  44. return;
  45. }
  46. auto rayTracingDeviceMask = RHI::RHISystemInterface::Get()->GetRayTracingSupport();
  47. m_diffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
  48. m_realTimeDiffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
  49. RHI::BufferPoolDescriptor desc;
  50. desc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  51. desc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  52. m_bufferPool = aznew RHI::MultiDeviceBufferPool;
  53. m_bufferPool->SetName(Name("DiffuseProbeGridBoxBufferPool"));
  54. [[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(RHI::MultiDevice::AllDevices, desc);
  55. AZ_Error("DiffuseProbeGridFeatureProcessor", resultCode == RHI::ResultCode::Success, "Failed to initialize buffer pool");
  56. // create box mesh vertices and indices
  57. CreateBoxMesh();
  58. // image pool
  59. {
  60. RHI::ImagePoolDescriptor imagePoolDesc;
  61. imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead;
  62. m_probeGridRenderData.m_imagePool = aznew RHI::MultiDeviceImagePool;
  63. m_probeGridRenderData.m_imagePool->SetName(Name("DiffuseProbeGridRenderImageData"));
  64. [[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(RHI::MultiDevice::AllDevices, imagePoolDesc);
  65. AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize output image pool");
  66. }
  67. // buffer pool
  68. {
  69. RHI::BufferPoolDescriptor bufferPoolDesc;
  70. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite;
  71. m_probeGridRenderData.m_bufferPool = aznew RHI::MultiDeviceBufferPool;
  72. m_probeGridRenderData.m_bufferPool->SetName(Name("DiffuseProbeGridRenderBufferData"));
  73. [[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_bufferPool->Init(RHI::MultiDevice::AllDevices, bufferPoolDesc);
  74. AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize output buffer pool");
  75. }
  76. // create image view descriptors
  77. m_probeGridRenderData.m_probeRayTraceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::RayTraceImageFormat, 0, 0);
  78. m_probeGridRenderData.m_probeIrradianceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::IrradianceImageFormat, 0, 0);
  79. m_probeGridRenderData.m_probeDistanceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::DistanceImageFormat, 0, 0);
  80. m_probeGridRenderData.m_probeDataImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::ProbeDataImageFormat, 0, 0);
  81. // create grid data buffer descriptor
  82. m_probeGridRenderData.m_gridDataBufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, 1, DiffuseProbeGridRenderData::GridDataBufferSize);
  83. // load shader
  84. // Note: the shader may not be available on all platforms
  85. Data::Instance<RPI::Shader> shader = RPI::LoadCriticalShader("Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRender.azshader");
  86. if (shader)
  87. {
  88. m_probeGridRenderData.m_drawListTag = shader->GetDrawListTag();
  89. m_probeGridRenderData.m_pipelineState = aznew RPI::PipelineStateForDraw;
  90. m_probeGridRenderData.m_pipelineState->Init(shader); // uses default shader variant
  91. m_probeGridRenderData.m_pipelineState->SetInputStreamLayout(m_boxStreamLayout);
  92. m_probeGridRenderData.m_pipelineState->SetOutputFromScene(GetParentScene());
  93. m_probeGridRenderData.m_pipelineState->Finalize();
  94. // load object shader resource group
  95. m_probeGridRenderData.m_shader = shader;
  96. m_probeGridRenderData.m_srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Object);
  97. AZ_Error("DiffuseProbeGridFeatureProcessor", m_probeGridRenderData.m_srgLayout != nullptr, "Failed to find ObjectSrg layout");
  98. }
  99. if (rayTracingDeviceMask != RHI::MultiDevice::NoDevices)
  100. {
  101. // initialize the buffer pools for the DiffuseProbeGrid visualization
  102. m_visualizationBufferPools = aznew RHI::MultiDeviceRayTracingBufferPools;
  103. m_visualizationBufferPools->Init(rayTracingDeviceMask);
  104. // load probe visualization model, the BLAS will be created in OnAssetReady()
  105. // The asset ID for our visualization model has the ID from the lowercased relative path of the source asset
  106. // and a sub ID that's generated based on the asset name.
  107. // The asset sub id is hardcoded here because the sub id is generated based on the asset name
  108. // and the generation method for models currently only exists in ModelAssetBuilderComponent::CreateAssetId().
  109. // It isn't exposed to the engine.
  110. // Note that there's technically a bug where if the DiffuseProbeSphere asset hasn't been processed by the Asset
  111. // Processor by the time this loads, it will load the default missing asset (a cube) instead of the sphere asset
  112. // until the next run of the Editor. This could be fixed by using the MeshFeatureProcessor to load the asset and
  113. // using ConnectModelChangeEventHandler() to listen for model changes to refresh the visualization.
  114. // However, since that will just cause the visualization to change from a cube to a sphere on the first run of the
  115. // Editor, handling the edge case might be overkill.
  116. Data::AssetId modelAssetId = Data::AssetId(AZ::Uuid::CreateName("models/diffuseprobesphere.fbx"), 268692035);
  117. m_visualizationModelAsset =
  118. Data::AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(modelAssetId, Data::AssetLoadBehavior::PreLoad);
  119. if (m_visualizationModelAsset.GetId().IsValid())
  120. {
  121. if (!m_visualizationModelAsset.IsReady())
  122. {
  123. m_visualizationModelAsset.QueueLoad();
  124. }
  125. Data::AssetBus::MultiHandler::BusConnect(m_visualizationModelAsset.GetId());
  126. }
  127. }
  128. // query buffer attachmentId
  129. AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
  130. m_queryBufferAttachmentId = AZStd::string::format("DiffuseProbeGridQueryBuffer_%s", uuidString.c_str());
  131. // cache the SpecularReflectionsFeatureProcessor and SSR RayTracing state
  132. m_specularReflectionsFeatureProcessor = GetParentScene()->GetFeatureProcessor<SpecularReflectionsFeatureProcessorInterface>();
  133. if (m_specularReflectionsFeatureProcessor)
  134. {
  135. const SSROptions& ssrOptions = m_specularReflectionsFeatureProcessor->GetSSROptions();
  136. m_ssrRayTracingEnabled = ssrOptions.IsRayTracingEnabled();
  137. }
  138. EnableSceneNotification();
  139. }
  140. void DiffuseProbeGridFeatureProcessor::Deactivate()
  141. {
  142. if (!AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED)
  143. {
  144. // GI is not supported on this platform
  145. return;
  146. }
  147. AZ_Warning("DiffuseProbeGridFeatureProcessor", m_diffuseProbeGrids.size() == 0,
  148. "Deactivating the DiffuseProbeGridFeatureProcessor, but there are still outstanding probe grids probes. Components\n"
  149. "using DiffuseProbeGridHandles should free them before the DiffuseProbeGridFeatureProcessor is deactivated.\n"
  150. );
  151. DisableSceneNotification();
  152. if (m_bufferPool)
  153. {
  154. m_bufferPool.reset();
  155. }
  156. Data::AssetBus::MultiHandler::BusDisconnect();
  157. }
  158. void DiffuseProbeGridFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
  159. {
  160. AZ_PROFILE_SCOPE(AzRender, "DiffuseProbeGridFeatureProcessor: Simulate");
  161. // update pipeline states
  162. if (m_needUpdatePipelineStates)
  163. {
  164. UpdatePipelineStates();
  165. m_needUpdatePipelineStates = false;
  166. }
  167. // check pending textures and connect bus for notifications
  168. for (auto& notificationEntry : m_notifyTextureAssets)
  169. {
  170. if (notificationEntry.m_assetId.IsValid())
  171. {
  172. // asset already has an assetId
  173. continue;
  174. }
  175. // query for the assetId
  176. AZ::Data::AssetId assetId;
  177. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  178. assetId,
  179. &AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
  180. notificationEntry.m_relativePath.c_str(),
  181. azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
  182. false);
  183. if (assetId.IsValid())
  184. {
  185. notificationEntry.m_assetId = assetId;
  186. notificationEntry.m_asset.Create(assetId, true);
  187. Data::AssetBus::MultiHandler::BusConnect(assetId);
  188. }
  189. }
  190. // if the volumes changed we need to re-sort the probe list
  191. if (m_probeGridSortRequired)
  192. {
  193. AZ_PROFILE_SCOPE(AzRender, "Sort diffuse probe grids");
  194. // sort the probes by descending inner volume size, so the smallest volumes are rendered last
  195. auto sortFn = [](AZStd::shared_ptr<DiffuseProbeGrid> const& probe1, AZStd::shared_ptr<DiffuseProbeGrid> const& probe2) -> bool
  196. {
  197. const Obb& obb1 = probe1->GetObbWs();
  198. const Obb& obb2 = probe2->GetObbWs();
  199. float size1 = obb1.GetHalfLengthX() * obb1.GetHalfLengthZ() * obb1.GetHalfLengthY();
  200. float size2 = obb2.GetHalfLengthX() * obb2.GetHalfLengthZ() * obb2.GetHalfLengthY();
  201. return (size1 > size2);
  202. };
  203. AZStd::sort(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), sortFn);
  204. AZStd::sort(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), sortFn);
  205. m_probeGridSortRequired = false;
  206. }
  207. // call Simulate on all diffuse probe grids
  208. for (uint32_t probeGridIndex = 0; probeGridIndex < m_diffuseProbeGrids.size(); ++probeGridIndex)
  209. {
  210. AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid = m_diffuseProbeGrids[probeGridIndex];
  211. AZ_Assert(diffuseProbeGrid.use_count() > 1, "DiffuseProbeGrid found with no corresponding owner, ensure that RemoveProbe() is called before releasing probe handles");
  212. diffuseProbeGrid->Simulate(probeGridIndex);
  213. }
  214. if (m_specularReflectionsFeatureProcessor)
  215. {
  216. const SSROptions& ssrOptions = m_specularReflectionsFeatureProcessor->GetSSROptions();
  217. if (m_ssrRayTracingEnabled != ssrOptions.IsRayTracingEnabled())
  218. {
  219. m_ssrRayTracingEnabled = ssrOptions.IsRayTracingEnabled();
  220. AZStd::vector<Name> passHierarchy = { Name("ReflectionScreenSpacePass"), Name("DiffuseProbeGridQueryFullscreenWithAlbedoPass") };
  221. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy);
  222. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  223. {
  224. pass->SetEnabled(m_ssrRayTracingEnabled);
  225. return RPI::PassFilterExecutionFlow::StopVisitingPasses;
  226. });
  227. }
  228. }
  229. }
  230. void DiffuseProbeGridFeatureProcessor::OnBeginPrepareRender()
  231. {
  232. for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids)
  233. {
  234. diffuseProbeGrid->ResetCullingVisibility();
  235. }
  236. // build the query buffer for the irradiance queries (if any)
  237. if (m_irradianceQueries.size())
  238. {
  239. m_queryBuffer.AdvanceCurrentBufferAndUpdateData(m_irradianceQueries);
  240. // create the bufferview descriptor with the new number of elements
  241. m_queryBufferViewDescriptor = m_queryBuffer.GetCurrentBuffer()->GetBufferViewDescriptor();
  242. }
  243. }
  244. void DiffuseProbeGridFeatureProcessor::OnEndPrepareRender()
  245. {
  246. // re-build the list of visible diffuse probe grids
  247. m_visibleDiffuseProbeGrids.clear();
  248. m_visibleRealTimeDiffuseProbeGrids.clear();
  249. for (auto& diffuseProbeGrid : m_diffuseProbeGrids)
  250. {
  251. if (diffuseProbeGrid->GetIsVisible())
  252. {
  253. if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime)
  254. {
  255. m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
  256. }
  257. m_visibleDiffuseProbeGrids.push_back(diffuseProbeGrid);
  258. }
  259. }
  260. }
  261. DiffuseProbeGridHandle DiffuseProbeGridFeatureProcessor::AddProbeGrid(const AZ::Transform& transform, const AZ::Vector3& extents, const AZ::Vector3& probeSpacing)
  262. {
  263. AZStd::shared_ptr<DiffuseProbeGrid> diffuseProbeGrid = AZStd::make_shared<DiffuseProbeGrid>();
  264. diffuseProbeGrid->Init(GetParentScene(), &m_probeGridRenderData);
  265. diffuseProbeGrid->SetTransform(transform);
  266. diffuseProbeGrid->SetExtents(extents);
  267. diffuseProbeGrid->SetProbeSpacing(probeSpacing);
  268. m_diffuseProbeGrids.push_back(diffuseProbeGrid);
  269. UpdateRealTimeList(diffuseProbeGrid);
  270. m_probeGridSortRequired = true;
  271. return diffuseProbeGrid;
  272. }
  273. void DiffuseProbeGridFeatureProcessor::RemoveProbeGrid(DiffuseProbeGridHandle& probeGrid)
  274. {
  275. AZ_Assert(probeGrid.get(), "RemoveProbeGrid called with an invalid handle");
  276. // remove from main list
  277. auto itEntry = AZStd::find_if(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  278. {
  279. return (entry == probeGrid);
  280. });
  281. AZ_Assert(itEntry != m_diffuseProbeGrids.end(), "RemoveProbeGrid called with a probe grid that is not in the probe list");
  282. m_diffuseProbeGrids.erase(itEntry);
  283. // remove from side list of real-time grids
  284. itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  285. {
  286. return (entry == probeGrid);
  287. });
  288. if (itEntry != m_realTimeDiffuseProbeGrids.end())
  289. {
  290. m_realTimeDiffuseProbeGrids.erase(itEntry);
  291. }
  292. // remove from side list of visible grids
  293. itEntry = AZStd::find_if(m_visibleDiffuseProbeGrids.begin(), m_visibleDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  294. {
  295. return (entry == probeGrid);
  296. });
  297. if (itEntry != m_visibleDiffuseProbeGrids.end())
  298. {
  299. m_visibleDiffuseProbeGrids.erase(itEntry);
  300. }
  301. // remove from side list of visible real-time grids
  302. itEntry = AZStd::find_if(m_visibleRealTimeDiffuseProbeGrids.begin(), m_visibleRealTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  303. {
  304. return (entry == probeGrid);
  305. });
  306. if (itEntry != m_visibleRealTimeDiffuseProbeGrids.end())
  307. {
  308. m_visibleRealTimeDiffuseProbeGrids.erase(itEntry);
  309. }
  310. probeGrid = nullptr;
  311. }
  312. bool DiffuseProbeGridFeatureProcessor::ValidateExtents(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& newExtents)
  313. {
  314. AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
  315. return probeGrid->ValidateExtents(newExtents);
  316. }
  317. void DiffuseProbeGridFeatureProcessor::SetExtents(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& extents)
  318. {
  319. AZ_Assert(probeGrid.get(), "SetExtents called with an invalid handle");
  320. probeGrid->SetExtents(extents);
  321. m_probeGridSortRequired = true;
  322. }
  323. void DiffuseProbeGridFeatureProcessor::SetTransform(const DiffuseProbeGridHandle& probeGrid, const AZ::Transform& transform)
  324. {
  325. AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
  326. probeGrid->SetTransform(transform);
  327. m_probeGridSortRequired = true;
  328. }
  329. bool DiffuseProbeGridFeatureProcessor::ValidateProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& newSpacing)
  330. {
  331. AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
  332. return probeGrid->ValidateProbeSpacing(newSpacing);
  333. }
  334. void DiffuseProbeGridFeatureProcessor::SetProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& probeSpacing)
  335. {
  336. AZ_Assert(probeGrid.get(), "SetProbeSpacing called with an invalid handle");
  337. probeGrid->SetProbeSpacing(probeSpacing);
  338. }
  339. void DiffuseProbeGridFeatureProcessor::SetViewBias(const DiffuseProbeGridHandle& probeGrid, float viewBias)
  340. {
  341. AZ_Assert(probeGrid.get(), "SetViewBias called with an invalid handle");
  342. probeGrid->SetViewBias(viewBias);
  343. }
  344. void DiffuseProbeGridFeatureProcessor::SetNormalBias(const DiffuseProbeGridHandle& probeGrid, float normalBias)
  345. {
  346. AZ_Assert(probeGrid.get(), "SetNormalBias called with an invalid handle");
  347. probeGrid->SetNormalBias(normalBias);
  348. }
  349. void DiffuseProbeGridFeatureProcessor::SetNumRaysPerProbe(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridNumRaysPerProbe numRaysPerProbe)
  350. {
  351. AZ_Assert(probeGrid.get(), "SetNumRaysPerProbe called with an invalid handle");
  352. probeGrid->SetNumRaysPerProbe(numRaysPerProbe);
  353. }
  354. void DiffuseProbeGridFeatureProcessor::SetAmbientMultiplier(const DiffuseProbeGridHandle& probeGrid, float ambientMultiplier)
  355. {
  356. AZ_Assert(probeGrid.get(), "SetAmbientMultiplier called with an invalid handle");
  357. probeGrid->SetAmbientMultiplier(ambientMultiplier);
  358. }
  359. void DiffuseProbeGridFeatureProcessor::Enable(const DiffuseProbeGridHandle& probeGrid, bool enable)
  360. {
  361. AZ_Assert(probeGrid.get(), "Enable called with an invalid handle");
  362. probeGrid->Enable(enable);
  363. }
  364. void DiffuseProbeGridFeatureProcessor::SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows)
  365. {
  366. AZ_Assert(probeGrid.get(), "SetGIShadows called with an invalid handle");
  367. probeGrid->SetGIShadows(giShadows);
  368. }
  369. void DiffuseProbeGridFeatureProcessor::SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl)
  370. {
  371. AZ_Assert(probeGrid.get(), "SetUseDiffuseIbl called with an invalid handle");
  372. probeGrid->SetUseDiffuseIbl(useDiffuseIbl);
  373. }
  374. bool DiffuseProbeGridFeatureProcessor::CanBakeTextures()
  375. {
  376. return RHI::RHISystemInterface::Get()->GetRayTracingSupport() != RHI::MultiDevice::NoDevices;
  377. }
  378. void DiffuseProbeGridFeatureProcessor::BakeTextures(
  379. const DiffuseProbeGridHandle& probeGrid,
  380. DiffuseProbeGridBakeTexturesCallback callback,
  381. const AZStd::string& irradianceTextureRelativePath,
  382. const AZStd::string& distanceTextureRelativePath,
  383. const AZStd::string& probeDataTextureRelativePath)
  384. {
  385. AZ_Assert(probeGrid.get(), "BakeTextures called with an invalid handle");
  386. AddNotificationEntry(irradianceTextureRelativePath);
  387. AddNotificationEntry(distanceTextureRelativePath);
  388. AddNotificationEntry(probeDataTextureRelativePath);
  389. probeGrid->GetTextureReadback().BeginTextureReadback(callback);
  390. }
  391. void DiffuseProbeGridFeatureProcessor::UpdateRealTimeList(const DiffuseProbeGridHandle& diffuseProbeGrid)
  392. {
  393. if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime)
  394. {
  395. // add to side list of real-time grids
  396. auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  397. {
  398. return (entry == diffuseProbeGrid);
  399. });
  400. if (itEntry == m_realTimeDiffuseProbeGrids.end())
  401. {
  402. m_realTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
  403. }
  404. }
  405. else
  406. {
  407. // remove from side list of real-time grids
  408. auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
  409. {
  410. return (entry == diffuseProbeGrid);
  411. });
  412. if (itEntry != m_realTimeDiffuseProbeGrids.end())
  413. {
  414. m_realTimeDiffuseProbeGrids.erase(itEntry);
  415. }
  416. }
  417. }
  418. void DiffuseProbeGridFeatureProcessor::AddNotificationEntry(const AZStd::string& relativePath)
  419. {
  420. AZStd::string assetPath = relativePath + ".streamingimage";
  421. // check to see if this is an existing asset
  422. AZ::Data::AssetId assetId;
  423. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  424. assetId,
  425. &AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
  426. assetPath.c_str(),
  427. azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
  428. false);
  429. // We only track notifications for new texture assets, meaning assets that are created the first time a DiffuseProbeGrid is baked.
  430. // On subsequent bakes the existing assets are automatically reloaded by the RPI since they are already known by the asset system.
  431. if (!assetId.IsValid())
  432. {
  433. m_notifyTextureAssets.push_back({ assetPath, assetId });
  434. }
  435. }
  436. bool DiffuseProbeGridFeatureProcessor::CheckTextureAssetNotification(
  437. const AZStd::string& relativePath,
  438. Data::Asset<RPI::StreamingImageAsset>& outTextureAsset,
  439. DiffuseProbeGridTextureNotificationType& outNotificationType)
  440. {
  441. for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
  442. {
  443. if (itNotification->m_relativePath == relativePath)
  444. {
  445. outNotificationType = itNotification->m_notificationType;
  446. if (outNotificationType != DiffuseProbeGridTextureNotificationType::None)
  447. {
  448. outTextureAsset = itNotification->m_asset;
  449. m_notifyTextureAssets.erase(itNotification);
  450. }
  451. return true;
  452. }
  453. }
  454. return false;
  455. }
  456. bool DiffuseProbeGridFeatureProcessor::AreBakedTexturesReferenced(
  457. const AZStd::string& irradianceTextureRelativePath,
  458. const AZStd::string& distanceTextureRelativePath,
  459. const AZStd::string& probeDataTextureRelativePath)
  460. {
  461. for (auto& diffuseProbeGrid : m_diffuseProbeGrids)
  462. {
  463. if ((diffuseProbeGrid->GetBakedIrradianceRelativePath() == irradianceTextureRelativePath) ||
  464. (diffuseProbeGrid->GetBakedDistanceRelativePath() == distanceTextureRelativePath) ||
  465. (diffuseProbeGrid->GetBakedProbeDataRelativePath() == probeDataTextureRelativePath))
  466. {
  467. return true;
  468. }
  469. }
  470. return false;
  471. }
  472. void DiffuseProbeGridFeatureProcessor::SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode)
  473. {
  474. AZ_Assert(probeGrid.get(), "SetMode called with an invalid handle");
  475. probeGrid->SetMode(mode);
  476. UpdateRealTimeList(probeGrid);
  477. m_probeGridSortRequired = true;
  478. }
  479. void DiffuseProbeGridFeatureProcessor::SetScrolling(const DiffuseProbeGridHandle& probeGrid, bool scrolling)
  480. {
  481. AZ_Assert(probeGrid.get(), "SetScrolling called with an invalid handle");
  482. probeGrid->SetScrolling(scrolling);
  483. }
  484. void DiffuseProbeGridFeatureProcessor::SetEdgeBlendIbl(const DiffuseProbeGridHandle& probeGrid, bool edgeBlendIbl)
  485. {
  486. AZ_Assert(probeGrid.get(), "SetEdgeBlendIbl called with an invalid handle");
  487. probeGrid->SetEdgeBlendIbl(edgeBlendIbl);
  488. }
  489. void DiffuseProbeGridFeatureProcessor::SetFrameUpdateCount(const DiffuseProbeGridHandle& probeGrid, uint32_t frameUpdateCount)
  490. {
  491. AZ_Assert(probeGrid.get(), "SetFrameUpdateCount called with an invalid handle");
  492. probeGrid->SetFrameUpdateCount(frameUpdateCount);
  493. }
  494. void DiffuseProbeGridFeatureProcessor::SetTransparencyMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridTransparencyMode transparencyMode)
  495. {
  496. AZ_Assert(probeGrid.get(), "SetTransparencyMode called with an invalid handle");
  497. probeGrid->SetTransparencyMode(transparencyMode);
  498. }
  499. void DiffuseProbeGridFeatureProcessor::SetEmissiveMultiplier(const DiffuseProbeGridHandle& probeGrid, float emissiveMultiplier)
  500. {
  501. AZ_Assert(probeGrid.get(), "SetEmissiveMultiplier called with an invalid handle");
  502. probeGrid->SetEmissiveMultiplier(emissiveMultiplier);
  503. }
  504. void DiffuseProbeGridFeatureProcessor::SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures)
  505. {
  506. AZ_Assert(probeGrid.get(), "SetBakedTextures called with an invalid handle");
  507. probeGrid->SetBakedTextures(bakedTextures);
  508. }
  509. void DiffuseProbeGridFeatureProcessor::SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled)
  510. {
  511. AZ_Assert(probeGrid.get(), "SetVisualizationEnabled called with an invalid handle");
  512. probeGrid->SetVisualizationEnabled(visualizationEnabled);
  513. }
  514. void DiffuseProbeGridFeatureProcessor::SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes)
  515. {
  516. AZ_Assert(probeGrid.get(), "SetVisualizationShowInactiveProbes called with an invalid handle");
  517. probeGrid->SetVisualizationShowInactiveProbes(visualizationShowInactiveProbes);
  518. }
  519. void DiffuseProbeGridFeatureProcessor::SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius)
  520. {
  521. AZ_Assert(probeGrid.get(), "SetVisualizationSphereRadius called with an invalid handle");
  522. probeGrid->SetVisualizationSphereRadius(visualizationSphereRadius);
  523. }
  524. uint32_t DiffuseProbeGridFeatureProcessor::AddIrradianceQuery(const AZ::Vector3& position, const AZ::Vector3& direction)
  525. {
  526. m_irradianceQueries.push_back({ position, direction });
  527. return aznumeric_cast<uint32_t>(m_irradianceQueries.size()) - 1;
  528. }
  529. void DiffuseProbeGridFeatureProcessor::ClearIrradianceQueries()
  530. {
  531. m_irradianceQueries.clear();
  532. }
  533. void DiffuseProbeGridFeatureProcessor::CreateBoxMesh()
  534. {
  535. // vertex positions
  536. static const Position positions[] =
  537. {
  538. // front
  539. { -0.5f, -0.5f, 0.5f },
  540. { 0.5f, -0.5f, 0.5f },
  541. { 0.5f, 0.5f, 0.5f },
  542. { -0.5f, 0.5f, 0.5f },
  543. // back
  544. { -0.5f, -0.5f, -0.5f },
  545. { 0.5f, -0.5f, -0.5f },
  546. { 0.5f, 0.5f, -0.5f },
  547. { -0.5f, 0.5f, -0.5f },
  548. // left
  549. { -0.5f, -0.5f, 0.5f },
  550. { -0.5f, 0.5f, 0.5f },
  551. { -0.5f, 0.5f, -0.5f },
  552. { -0.5f, -0.5f, -0.5f },
  553. // right
  554. { 0.5f, -0.5f, 0.5f },
  555. { 0.5f, 0.5f, 0.5f },
  556. { 0.5f, 0.5f, -0.5f },
  557. { 0.5f, -0.5f, -0.5f },
  558. // bottom
  559. { -0.5f, -0.5f, 0.5f },
  560. { 0.5f, -0.5f, 0.5f },
  561. { 0.5f, -0.5f, -0.5f },
  562. { -0.5f, -0.5f, -0.5f },
  563. // top
  564. { -0.5f, 0.5f, 0.5f },
  565. { 0.5f, 0.5f, 0.5f },
  566. { 0.5f, 0.5f, -0.5f },
  567. { -0.5f, 0.5f, -0.5f },
  568. };
  569. static const u32 numPositions = sizeof(positions) / sizeof(positions[0]);
  570. for (u32 i = 0; i < numPositions; ++i)
  571. {
  572. m_boxPositions.push_back(positions[i]);
  573. }
  574. // indices
  575. static const uint16_t indices[] =
  576. {
  577. // front
  578. 0, 1, 2, 2, 3, 0,
  579. // back
  580. 5, 4, 7, 7, 6, 5,
  581. // left
  582. 8, 9, 10, 10, 11, 8,
  583. // right
  584. 14, 13, 12, 12, 15, 14,
  585. // bottom
  586. 18, 17, 16, 16, 19, 18,
  587. // top
  588. 23, 20, 21, 21, 22, 23
  589. };
  590. static const u32 numIndices = sizeof(indices) / sizeof(indices[0]);
  591. for (u32 i = 0; i < numIndices; ++i)
  592. {
  593. m_boxIndices.push_back(indices[i]);
  594. }
  595. // create stream layout
  596. RHI::InputStreamLayoutBuilder layoutBuilder;
  597. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  598. layoutBuilder.SetTopology(RHI::PrimitiveTopology::TriangleList);
  599. m_boxStreamLayout = layoutBuilder.End();
  600. // create index buffer
  601. AZ::RHI::MultiDeviceBufferInitRequest request;
  602. m_boxIndexBuffer = aznew RHI::MultiDeviceBuffer;
  603. request.m_buffer = m_boxIndexBuffer.get();
  604. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) };
  605. request.m_initialData = m_boxIndices.data();
  606. [[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
  607. AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
  608. // create index buffer view
  609. AZ::RHI::MultiDeviceIndexBufferView indexBufferView =
  610. {
  611. *m_boxIndexBuffer,
  612. 0,
  613. sizeof(indices),
  614. AZ::RHI::IndexFormat::Uint16,
  615. };
  616. m_probeGridRenderData.m_boxIndexBufferView = indexBufferView;
  617. m_probeGridRenderData.m_boxIndexCount = numIndices;
  618. // create position buffer
  619. m_boxPositionBuffer = aznew RHI::MultiDeviceBuffer;
  620. request.m_buffer = m_boxPositionBuffer.get();
  621. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxPositions.size() * sizeof(Position) };
  622. request.m_initialData = m_boxPositions.data();
  623. result = m_bufferPool->InitBuffer(request);
  624. AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
  625. // create position buffer view
  626. RHI::MultiDeviceStreamBufferView positionBufferView =
  627. {
  628. *m_boxPositionBuffer,
  629. 0,
  630. (uint32_t)(m_boxPositions.size() * sizeof(Position)),
  631. sizeof(Position),
  632. };
  633. m_probeGridRenderData.m_boxPositionBufferView = { { positionBufferView } };
  634. AZ::RHI::ValidateStreamBufferViews(m_boxStreamLayout, m_probeGridRenderData.m_boxPositionBufferView);
  635. }
  636. void DiffuseProbeGridFeatureProcessor::OnRenderPipelineChanged(RPI::RenderPipeline* renderPipeline,
  637. RPI::SceneNotification::RenderPipelineChangeType changeType)
  638. {
  639. if (changeType == RPI::SceneNotification::RenderPipelineChangeType::PassChanged)
  640. {
  641. // change the attachment on the AuxGeom pass to use the output of the visualization pass
  642. RPI::PassFilter auxGeomPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("AuxGeomPass"), renderPipeline);
  643. RPI::Pass* auxGeomPass = RPI::PassSystemInterface::Get()->FindFirstPass(auxGeomPassFilter);
  644. RPI::PassFilter visualizationPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridVisualizationPass"), renderPipeline);
  645. RPI::Pass* visualizationPass = RPI::PassSystemInterface::Get()->FindFirstPass(visualizationPassFilter);
  646. if (auxGeomPass && visualizationPass && visualizationPass->GetInputOutputCount())
  647. {
  648. RPI::PassAttachmentBinding& visualizationBinding = visualizationPass->GetInputOutputBinding(0);
  649. RPI::PassAttachmentBinding* auxGeomBinding = auxGeomPass->FindAttachmentBinding(AZ::Name("ColorInputOutput"));
  650. if (auxGeomBinding)
  651. {
  652. auxGeomBinding->SetAttachment(visualizationBinding.GetAttachment());
  653. }
  654. }
  655. UpdatePasses();
  656. }
  657. m_needUpdatePipelineStates = true;
  658. }
  659. void DiffuseProbeGridFeatureProcessor::AddRenderPasses(AZ::RPI::RenderPipeline* renderPipeline)
  660. {
  661. // only add to this pipeline if it contains the DiffuseGlobalFullscreen pass
  662. RPI::PassFilter diffuseGlobalFullscreenPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseGlobalFullscreenPass"), renderPipeline);
  663. RPI::Pass* diffuseGlobalFullscreenPass = RPI::PassSystemInterface::Get()->FindFirstPass(diffuseGlobalFullscreenPassFilter);
  664. if (!diffuseGlobalFullscreenPass)
  665. {
  666. return;
  667. }
  668. // check to see if the DiffuseProbeGrid passes were already added
  669. RPI::PassFilter diffuseProbeGridUpdatePassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), renderPipeline);
  670. RPI::Pass* diffuseProbeGridUpdatePass = RPI::PassSystemInterface::Get()->FindFirstPass(diffuseProbeGridUpdatePassFilter);
  671. if (!diffuseProbeGridUpdatePass)
  672. {
  673. AddPassRequest(renderPipeline, "Passes/DiffuseProbeGridPreparePassRequest.azasset", "DepthPrePass");
  674. AddPassRequest(renderPipeline, "Passes/DiffuseProbeGridUpdatePassRequest.azasset", "DiffuseProbeGridPreparePass");
  675. AddPassRequest(renderPipeline, "Passes/DiffuseProbeGridRenderPassRequest.azasset", "ForwardSubsurface");
  676. // add the fullscreen query pass for SSR raytracing fallback color
  677. AddPassRequest(renderPipeline, "Passes/DiffuseProbeGridScreenSpaceReflectionsQueryPassRequest.azasset", "ReflectionScreenSpaceRayTracingPass");
  678. // only add the visualization pass if there's an AuxGeom pass in the pipeline
  679. RPI::PassFilter auxGeomPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("AuxGeomPass"), renderPipeline);
  680. RPI::Pass* auxGeomPass = RPI::PassSystemInterface::Get()->FindFirstPass(auxGeomPassFilter);
  681. if (auxGeomPass)
  682. {
  683. AddPassRequest(renderPipeline, "Passes/DiffuseProbeGridVisualizationPassRequest.azasset", "PostProcessPass");
  684. }
  685. // disable the DiffuseGlobalFullscreenPass if it exists, since it is replaced with a DiffuseProbeGrid composite pass
  686. diffuseGlobalFullscreenPass->SetEnabled(false);
  687. }
  688. UpdatePasses();
  689. m_needUpdatePipelineStates = true;
  690. }
  691. void DiffuseProbeGridFeatureProcessor::AddPassRequest(RPI::RenderPipeline* renderPipeline, const char* passRequestAssetFilePath, const char* insertionPointPassName)
  692. {
  693. auto passRequestAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::AnyAsset>(passRequestAssetFilePath, RPI::AssetUtils::TraceLevel::Warning);
  694. // load pass request from the asset
  695. const RPI::PassRequest* passRequest = nullptr;
  696. if (passRequestAsset->IsReady())
  697. {
  698. passRequest = passRequestAsset->GetDataAs<RPI::PassRequest>();
  699. }
  700. if (!passRequest)
  701. {
  702. AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load PassRequest asset [%s]", passRequestAssetFilePath);
  703. return;
  704. }
  705. // check to see if the pass already exists
  706. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passRequest->m_passName, renderPipeline);
  707. RPI::Pass* existingPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
  708. if (existingPass)
  709. {
  710. return;
  711. }
  712. // create tha pass from the request
  713. RPI::Ptr<RPI::Pass> newPass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(passRequest);
  714. if (!newPass)
  715. {
  716. AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to create pass from pass request [%s]", passRequest->m_passName.GetCStr());
  717. return;
  718. }
  719. // Add the pass to render pipeline
  720. bool success = renderPipeline->AddPassAfter(newPass, AZ::Name(insertionPointPassName));
  721. if (!success)
  722. {
  723. AZ_Warning("DiffuseProbeGridFeatureProcessor", false, "Failed to add pass [%s] to render pipeline [%s]", newPass->GetName().GetCStr(), renderPipeline->GetId().GetCStr());
  724. }
  725. }
  726. void DiffuseProbeGridFeatureProcessor::UpdatePipelineStates()
  727. {
  728. if (m_probeGridRenderData.m_pipelineState)
  729. {
  730. m_probeGridRenderData.m_pipelineState->SetOutputFromScene(GetParentScene());
  731. m_probeGridRenderData.m_pipelineState->Finalize();
  732. }
  733. }
  734. void DiffuseProbeGridFeatureProcessor::UpdatePasses()
  735. {
  736. // disable the DiffuseProbeGridUpdatePass if the platform does not support raytracing
  737. if (RHI::RHISystemInterface::Get()->GetRayTracingSupport() == RHI::MultiDevice::NoDevices)
  738. {
  739. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene());
  740. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  741. {
  742. pass->SetEnabled(false);
  743. return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  744. });
  745. }
  746. }
  747. void DiffuseProbeGridFeatureProcessor::OnVisualizationModelAssetReady(Data::Asset<Data::AssetData> asset)
  748. {
  749. m_visualizationModel = RPI::Model::FindOrCreate(asset);
  750. AZ_Assert(m_visualizationModel.get(), "Failed to load DiffuseProbeGrid visualization model");
  751. if (!m_visualizationModel)
  752. {
  753. return;
  754. }
  755. const AZStd::span<const Data::Instance<RPI::ModelLod>>& modelLods = m_visualizationModel->GetLods();
  756. AZ_Assert(!modelLods.empty(), "Invalid DiffuseProbeGrid visualization model");
  757. if (modelLods.empty())
  758. {
  759. return;
  760. }
  761. const Data::Instance<RPI::ModelLod>& modelLod = modelLods[0];
  762. AZ_Assert(!modelLod->GetMeshes().empty(), "Invalid DiffuseProbeGrid visualization model asset");
  763. if (modelLod->GetMeshes().empty())
  764. {
  765. return;
  766. }
  767. const auto meshes = modelLod->GetMeshes();
  768. const RPI::ModelLod::Mesh& mesh = meshes[0];
  769. // setup a stream layout and shader input contract for the position vertex stream
  770. static const char* PositionSemantic = "POSITION";
  771. static const RHI::Format PositionStreamFormat = RHI::Format::R32G32B32_FLOAT;
  772. RHI::InputStreamLayoutBuilder layoutBuilder;
  773. layoutBuilder.AddBuffer()->Channel(PositionSemantic, PositionStreamFormat);
  774. RHI::InputStreamLayout inputStreamLayout = layoutBuilder.End();
  775. RPI::ShaderInputContract::StreamChannelInfo positionStreamChannelInfo;
  776. positionStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(PositionSemantic));
  777. positionStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(PositionStreamFormat);
  778. RPI::ShaderInputContract shaderInputContract;
  779. shaderInputContract.m_streamChannels.emplace_back(positionStreamChannelInfo);
  780. // retrieve vertex/index buffers
  781. RPI::ModelLod::StreamBufferViewList streamBufferViews;
  782. [[maybe_unused]] bool result = modelLod->GetStreamsForMesh(
  783. inputStreamLayout,
  784. streamBufferViews,
  785. nullptr,
  786. shaderInputContract,
  787. 0);
  788. AZ_Assert(result, "Failed to retrieve DiffuseProbeGrid visualization mesh stream buffer views");
  789. m_visualizationVB = streamBufferViews[0];
  790. m_visualizationIB = mesh.m_indexBufferView;
  791. // create the BLAS object
  792. RHI::MultiDeviceRayTracingBlasDescriptor blasDescriptor;
  793. blasDescriptor.Build()
  794. ->Geometry()
  795. ->VertexFormat(PositionStreamFormat)
  796. ->VertexBuffer(m_visualizationVB)
  797. ->IndexBuffer(m_visualizationIB)
  798. ;
  799. RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
  800. m_visualizationBlas = aznew RHI::MultiDeviceRayTracingBlas;
  801. auto deviceMask = RHI::RHISystemInterface::Get()->GetRayTracingSupport();
  802. if (deviceMask != RHI::MultiDevice::NoDevices)
  803. {
  804. m_visualizationBlas->CreateBuffers(deviceMask, &blasDescriptor, *m_visualizationBufferPools);
  805. }
  806. }
  807. void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> asset, DiffuseProbeGridTextureNotificationType notificationType)
  808. {
  809. for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
  810. {
  811. if (itNotification->m_assetId == asset.GetId())
  812. {
  813. // store the texture asset
  814. itNotification->m_asset = Data::static_pointer_cast<RPI::StreamingImageAsset>(asset);
  815. itNotification->m_notificationType = notificationType;
  816. // stop notifications on this asset
  817. Data::AssetBus::MultiHandler::BusDisconnect(itNotification->m_assetId);
  818. break;
  819. }
  820. }
  821. }
  822. void DiffuseProbeGridFeatureProcessor::OnAssetReady(Data::Asset<Data::AssetData> asset)
  823. {
  824. if (asset.GetId() == m_visualizationModelAsset.GetId())
  825. {
  826. OnVisualizationModelAssetReady(asset);
  827. }
  828. else
  829. {
  830. HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready);
  831. }
  832. }
  833. void DiffuseProbeGridFeatureProcessor::OnAssetError(Data::Asset<Data::AssetData> asset)
  834. {
  835. if (asset.GetId() == m_visualizationModelAsset.GetId())
  836. {
  837. AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load probe visualization model asset [%s]", asset.GetHint().c_str());
  838. }
  839. else
  840. {
  841. AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str());
  842. HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error);
  843. }
  844. }
  845. } // namespace Render
  846. } // namespace AZ