DiffuseProbeGridFeatureProcessor.cpp 52 KB

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