3
0

DiffuseProbeGridFeatureProcessor.cpp 52 KB

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