ReflectionProbe.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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 <ReflectionProbe/ReflectionProbe.h>
  9. #include <ReflectionProbe/ReflectionProbeFeatureProcessor.h>
  10. #include <Atom/RHI/RHISystemInterface.h>
  11. #include <Atom/RPI.Public/Pass/Pass.h>
  12. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RPI.Public/View.h>
  15. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  16. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  17. #include <Atom/RPI.Reflect/Pass/EnvironmentCubeMapPassData.h>
  18. namespace AZ
  19. {
  20. namespace Render
  21. {
  22. ReflectionProbe::~ReflectionProbe()
  23. {
  24. Data::AssetBus::Handler::BusDisconnect();
  25. m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
  26. m_meshFeatureProcessor->ReleaseMesh(m_visualizationMeshHandle);
  27. }
  28. void ReflectionProbe::OnAssetReady(Data::Asset<Data::AssetData> asset)
  29. {
  30. if (m_visualizationMaterialAsset.GetId() == asset.GetId())
  31. {
  32. m_visualizationMaterialAsset = asset;
  33. Data::AssetBus::Handler::BusDisconnect();
  34. m_meshFeatureProcessor->SetCustomMaterials(m_visualizationMeshHandle, AZ::RPI::Material::FindOrCreate(m_visualizationMaterialAsset));
  35. }
  36. }
  37. void ReflectionProbe::OnAssetError(Data::Asset<Data::AssetData> asset)
  38. {
  39. AZ_Error("ReflectionProbe", false, "Failed to load ReflectionProbe dependency asset %s", asset.ToString<AZStd::string>().c_str());
  40. Data::AssetBus::Handler::BusDisconnect();
  41. }
  42. void ReflectionProbe::Init(RPI::Scene* scene, ReflectionRenderData* reflectionRenderData)
  43. {
  44. AZ_Assert(scene, "ReflectionProbe::Init called with a null Scene pointer");
  45. m_scene = scene;
  46. m_reflectionRenderData = reflectionRenderData;
  47. CubeMapRenderer::SetScene(m_scene);
  48. // load visualization sphere model and material
  49. m_meshFeatureProcessor = m_scene->GetFeatureProcessor<Render::MeshFeatureProcessorInterface>();
  50. // We don't have to pre-load this asset before passing it to MeshFeatureProcessor, because the MeshFeatureProcessor will handle the async-load for us.
  51. m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
  52. "Models/ReflectionProbeSphere.fbx.azmodel",
  53. AZ::RPI::AssetUtils::TraceLevel::Assert);
  54. MeshHandleDescriptor visualizationMeshDescriptor;
  55. visualizationMeshDescriptor.m_modelAsset = m_visualizationModelAsset;
  56. visualizationMeshDescriptor.m_isRayTracingEnabled = false;
  57. m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(visualizationMeshDescriptor);
  58. m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_visualizationMeshHandle, true);
  59. m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, AZ::Transform::CreateIdentity());
  60. // We have to pre-load this asset before creating a material instance because the InstanceDatabase will attempt a blocking load which could deadlock,
  61. // particularly when slices are involved.
  62. // Note that m_visualizationMeshHandle had to be set up first, because AssetBus BusConnect() might call ReflectionProbe::OnAssetReady() immediately on this callstack.
  63. m_visualizationMaterialAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::MaterialAsset>(
  64. "Materials/ReflectionProbe/ReflectionProbeVisualization.azmaterial",
  65. AZ::RPI::AssetUtils::TraceLevel::Assert);
  66. m_visualizationMaterialAsset.QueueLoad();
  67. Data::AssetBus::Handler::BusConnect(m_visualizationMaterialAsset.GetId());
  68. // reflection render Srgs
  69. m_stencilSrg = RPI::ShaderResourceGroup::Create(
  70. m_reflectionRenderData->m_stencilShader->GetAsset(),
  71. m_reflectionRenderData->m_stencilShader->GetSupervariantIndex(),
  72. m_reflectionRenderData->m_stencilSrgLayout->GetName());
  73. AZ_Error("ReflectionProbeFeatureProcessor", m_stencilSrg.get(), "Failed to create stencil shader resource group");
  74. m_blendWeightSrg = RPI::ShaderResourceGroup::Create(
  75. m_reflectionRenderData->m_blendWeightShader->GetAsset(),
  76. m_reflectionRenderData->m_blendWeightShader->GetSupervariantIndex(),
  77. m_reflectionRenderData->m_blendWeightSrgLayout->GetName());
  78. AZ_Error("ReflectionProbeFeatureProcessor", m_blendWeightSrg.get(), "Failed to create blend weight shader resource group");
  79. m_renderOuterSrg = RPI::ShaderResourceGroup::Create(
  80. m_reflectionRenderData->m_renderOuterShader->GetAsset(),
  81. m_reflectionRenderData->m_renderOuterShader->GetSupervariantIndex(),
  82. m_reflectionRenderData->m_renderOuterSrgLayout->GetName());
  83. AZ_Error("ReflectionProbeFeatureProcessor", m_renderOuterSrg.get(), "Failed to create render outer reflection shader resource group");
  84. m_renderInnerSrg = RPI::ShaderResourceGroup::Create(
  85. m_reflectionRenderData->m_renderInnerShader->GetAsset(),
  86. m_reflectionRenderData->m_renderInnerShader->GetSupervariantIndex(),
  87. m_reflectionRenderData->m_renderInnerSrgLayout->GetName());
  88. AZ_Error("ReflectionProbeFeatureProcessor", m_renderInnerSrg.get(), "Failed to create render inner reflection shader resource group");
  89. // setup culling
  90. m_cullable.SetDebugName(AZ::Name("ReflectionProbe Volume"));
  91. }
  92. void ReflectionProbe::Simulate(uint32_t probeIndex)
  93. {
  94. CubeMapRenderer::Update();
  95. // track if we need to update culling based on changes to the draw packets or Srg
  96. bool updateCulling = false;
  97. if (m_updateSrg)
  98. {
  99. // stencil Srg
  100. // Note: the stencil pass uses a slightly reduced inner OBB to avoid seams
  101. Vector3 innerExtentsReduced = m_innerExtents - Vector3(0.1f, 0.1f, 0.1f);
  102. Matrix3x4 modelToWorldStencil = Matrix3x4::CreateFromQuaternionAndTranslation(m_transform.GetRotation(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(innerExtentsReduced);
  103. m_stencilSrg->SetConstant(m_reflectionRenderData->m_modelToWorldStencilConstantIndex, modelToWorldStencil);
  104. m_stencilSrg->Compile();
  105. Matrix3x4 modelToWorldInverse = Matrix3x4::CreateFromTransform(m_transform).GetInverseFull();
  106. // blend weight Srg
  107. Matrix3x4 modelToWorldOuter = Matrix3x4::CreateFromQuaternionAndTranslation(m_transform.GetRotation(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_outerExtents);
  108. m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_modelToWorldRenderConstantIndex, modelToWorldOuter);
  109. m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_modelToWorldInverseRenderConstantIndex, modelToWorldInverse);
  110. m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths());
  111. m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths());
  112. m_blendWeightSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection);
  113. m_blendWeightSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage);
  114. m_blendWeightSrg->Compile();
  115. // render outer Srg
  116. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_modelToWorldRenderConstantIndex, modelToWorldOuter);
  117. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_modelToWorldInverseRenderConstantIndex, modelToWorldInverse);
  118. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths());
  119. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths());
  120. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection);
  121. m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure);
  122. m_renderOuterSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage);
  123. m_renderOuterSrg->Compile();
  124. // render inner Srg
  125. Matrix3x4 modelToWorldInner = Matrix3x4::CreateFromQuaternionAndTranslation(m_transform.GetRotation(), m_transform.GetTranslation()) * Matrix3x4::CreateScale(m_innerExtents);
  126. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_modelToWorldRenderConstantIndex, modelToWorldInner);
  127. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_modelToWorldInverseRenderConstantIndex, modelToWorldInverse);
  128. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths());
  129. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths());
  130. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection);
  131. m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure);
  132. m_renderInnerSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage);
  133. m_renderInnerSrg->Compile();
  134. m_updateSrg = false;
  135. updateCulling = true;
  136. }
  137. // the list index passed in from the feature processor is the index of this probe in the sorted probe list.
  138. // this is needed to render the probe volumes in order from largest to smallest
  139. RHI::DrawItemSortKey sortKey = static_cast<RHI::DrawItemSortKey>(probeIndex);
  140. if (sortKey != m_sortKey)
  141. {
  142. // the sort key changed, rebuild draw packets
  143. m_sortKey = sortKey;
  144. m_stencilDrawPacket = BuildDrawPacket(
  145. m_stencilSrg,
  146. m_reflectionRenderData->m_stencilPipelineState,
  147. m_reflectionRenderData->m_stencilDrawListTag,
  148. Render::StencilRefs::None);
  149. m_blendWeightDrawPacket = BuildDrawPacket(
  150. m_blendWeightSrg,
  151. m_reflectionRenderData->m_blendWeightPipelineState,
  152. m_reflectionRenderData->m_blendWeightDrawListTag,
  153. Render::StencilRefs::UseIBLSpecularPass);
  154. m_renderOuterDrawPacket = BuildDrawPacket(
  155. m_renderOuterSrg,
  156. m_reflectionRenderData->m_renderOuterPipelineState,
  157. m_reflectionRenderData->m_renderOuterDrawListTag,
  158. Render::StencilRefs::UseIBLSpecularPass);
  159. m_renderInnerDrawPacket = BuildDrawPacket(
  160. m_renderInnerSrg,
  161. m_reflectionRenderData->m_renderInnerPipelineState,
  162. m_reflectionRenderData->m_renderInnerDrawListTag,
  163. Render::StencilRefs::UseIBLSpecularPass);
  164. updateCulling = true;
  165. }
  166. if (updateCulling)
  167. {
  168. UpdateCulling();
  169. }
  170. }
  171. void ReflectionProbe::OnRenderEnd()
  172. {
  173. CubeMapRenderer::CheckAndRemovePipeline();
  174. }
  175. void ReflectionProbe::SetTransform(const AZ::Transform& transform)
  176. {
  177. // retrieve previous scale and revert the scale on the inner/outer extents
  178. float previousScale = m_transform.GetUniformScale();
  179. m_outerExtents /= previousScale;
  180. m_innerExtents /= previousScale;
  181. // store new transform
  182. m_transform = transform;
  183. // avoid scaling the visualization sphere
  184. AZ::Transform visualizationTransform = m_transform;
  185. visualizationTransform.ExtractUniformScale();
  186. m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, visualizationTransform);
  187. // update the inner/outer extents with the new scale
  188. m_outerExtents *= m_transform.GetUniformScale();
  189. m_innerExtents *= m_transform.GetUniformScale();
  190. m_outerObbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_outerExtents / 2.0f);
  191. m_innerObbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_innerExtents / 2.0f);
  192. m_updateSrg = true;
  193. }
  194. void ReflectionProbe::SetOuterExtents(const AZ::Vector3& outerExtents)
  195. {
  196. m_outerExtents = outerExtents * m_transform.GetUniformScale();
  197. m_outerObbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_outerExtents / 2.0f);
  198. m_updateSrg = true;
  199. }
  200. void ReflectionProbe::SetInnerExtents(const AZ::Vector3& innerExtents)
  201. {
  202. m_innerExtents = innerExtents * m_transform.GetUniformScale();
  203. m_innerObbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_innerExtents / 2.0f);
  204. m_updateSrg = true;
  205. }
  206. void ReflectionProbe::SetCubeMapImage(const Data::Instance<RPI::Image>& cubeMapImage, const AZStd::string& relativePath)
  207. {
  208. m_cubeMapImage = cubeMapImage;
  209. m_cubeMapRelativePath = relativePath;
  210. m_updateSrg = true;
  211. }
  212. void ReflectionProbe::Bake(RenderCubeMapCallback callback)
  213. {
  214. CubeMapRenderer::StartRender(callback, m_transform, m_bakeExposure);
  215. }
  216. void ReflectionProbe::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
  217. {
  218. CubeMapRenderer::SetDefaultView(renderPipeline);
  219. }
  220. void ReflectionProbe::ShowVisualization(bool showVisualization)
  221. {
  222. m_meshFeatureProcessor->SetVisible(m_visualizationMeshHandle, showVisualization);
  223. }
  224. void ReflectionProbe::SetRenderExposure(float renderExposure)
  225. {
  226. m_renderExposure = renderExposure;
  227. m_updateSrg = true;
  228. }
  229. void ReflectionProbe::SetBakeExposure(float bakeExposure)
  230. {
  231. m_bakeExposure = bakeExposure;
  232. }
  233. RHI::ConstPtr<RHI::DrawPacket> ReflectionProbe::BuildDrawPacket(
  234. const Data::Instance<RPI::ShaderResourceGroup>& srg,
  235. const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
  236. const RHI::DrawListTag& drawListTag,
  237. uint32_t stencilRef)
  238. {
  239. AZ_Assert(m_sortKey != InvalidSortKey, "Invalid probe sort key");
  240. if (pipelineState->GetRHIPipelineState() == nullptr)
  241. {
  242. return nullptr;
  243. }
  244. RHI::DrawPacketBuilder drawPacketBuilder{RHI::MultiDevice::AllDevices};
  245. drawPacketBuilder.Begin(nullptr);
  246. drawPacketBuilder.SetGeometryView(&m_reflectionRenderData->m_geometryView);
  247. drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup());
  248. RHI::DrawPacketBuilder::DrawRequest drawRequest;
  249. drawRequest.m_listTag = drawListTag;
  250. drawRequest.m_streamIndices = m_reflectionRenderData->m_geometryView.GetFullStreamBufferIndices();
  251. drawRequest.m_pipelineState = pipelineState->GetRHIPipelineState();
  252. drawRequest.m_stencilRef = static_cast<uint8_t>(stencilRef);
  253. drawRequest.m_sortKey = m_sortKey;
  254. drawPacketBuilder.AddDrawItem(drawRequest);
  255. return drawPacketBuilder.End();
  256. }
  257. void ReflectionProbe::UpdateCulling()
  258. {
  259. // set draw list mask
  260. m_cullable.m_cullData.m_drawListMask.reset();
  261. // check for draw packets due certain render pipelines such as lowend render pipeline that might not have this feature enabled
  262. if (m_stencilDrawPacket)
  263. {
  264. m_cullable.m_cullData.m_drawListMask |= m_stencilDrawPacket->GetDrawListMask();
  265. }
  266. if (m_blendWeightDrawPacket)
  267. {
  268. m_cullable.m_cullData.m_drawListMask |= m_blendWeightDrawPacket->GetDrawListMask();
  269. }
  270. if (m_renderOuterDrawPacket)
  271. {
  272. m_cullable.m_cullData.m_drawListMask |= m_renderOuterDrawPacket->GetDrawListMask();
  273. }
  274. if (m_renderInnerDrawPacket)
  275. {
  276. m_cullable.m_cullData.m_drawListMask |= m_renderInnerDrawPacket->GetDrawListMask();
  277. }
  278. // setup the Lod entry, using one entry for all four draw packets
  279. m_cullable.m_lodData.m_lods.clear();
  280. m_cullable.m_lodData.m_lods.resize(1);
  281. RPI::Cullable::LodData::Lod& lod = m_cullable.m_lodData.m_lods.back();
  282. // add draw packets
  283. lod.m_drawPackets.push_back(m_stencilDrawPacket.get());
  284. lod.m_drawPackets.push_back(m_blendWeightDrawPacket.get());
  285. lod.m_drawPackets.push_back(m_renderOuterDrawPacket.get());
  286. lod.m_drawPackets.push_back(m_renderInnerDrawPacket.get());
  287. // set screen coverage
  288. // probe volume should cover at least a screen pixel at 1080p to be drawn
  289. static const float MinimumScreenCoverage = 1.0f / 1080.0f;
  290. lod.m_screenCoverageMin = MinimumScreenCoverage;
  291. lod.m_screenCoverageMax = 1.0f;
  292. // update cullable bounds
  293. Aabb outerAabb = Aabb::CreateFromObb(m_outerObbWs);
  294. Vector3 center;
  295. float radius;
  296. outerAabb.GetAsSphere(center, radius);
  297. m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius);
  298. m_cullable.m_cullData.m_boundingObb = m_outerObbWs;
  299. m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = outerAabb;
  300. m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable;
  301. m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable;
  302. m_cullable.m_cullData.m_componentUuid = m_uuid;
  303. m_cullable.m_cullData.m_componentType = Culling::ComponentType::ReflectionProbe;
  304. // register with culling system
  305. m_scene->GetCullingScene()->RegisterOrUpdateCullable(m_cullable);
  306. }
  307. } // namespace Render
  308. } // namespace AZ