DiffuseProbeGridFeatureProcessor.cpp 47 KB

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