3
0

EnvironmentCubeMapPass.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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/Math/MatrixUtils.h>
  9. #include <Atom/RHI/FrameScheduler.h>
  10. #include <Atom/RHI/Factory.h>
  11. #include <Atom/RHI.Reflect/Format.h>
  12. #include <Atom/RPI.Public/Image/AttachmentImage.h>
  13. #include <Atom/RPI.Public/Image/AttachmentImagePool.h>
  14. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  15. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  16. #include <Atom/RPI.Public/Pass/PassUtils.h>
  17. #include <Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h>
  18. #include <Atom/RPI.Public/RenderPipeline.h>
  19. #include <Atom/RHI/RHISystemInterface.h>
  20. #include <Atom/RPI.Public/View.h>
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. Ptr<EnvironmentCubeMapPass> EnvironmentCubeMapPass::Create(const PassDescriptor& passDescriptor)
  26. {
  27. Ptr<EnvironmentCubeMapPass> pass = aznew EnvironmentCubeMapPass(passDescriptor);
  28. return pass;
  29. }
  30. EnvironmentCubeMapPass::EnvironmentCubeMapPass(const PassDescriptor& passDescriptor)
  31. : ParentPass(passDescriptor)
  32. {
  33. // load pass data
  34. const EnvironmentCubeMapPassData* passData = PassUtils::GetPassData<EnvironmentCubeMapPassData>(passDescriptor);
  35. if (passData == nullptr)
  36. {
  37. AZ_Error("PassSystem", false, "[EnvironmentCubeMapPass '%s']: Trying to construct without valid EnvironmentCubeMapPassData!", GetPathName().GetCStr());
  38. return;
  39. }
  40. m_position = passData->m_position;
  41. // create the cubemap pipeline as a child of this pass
  42. PassRequest childRequest;
  43. childRequest.m_templateName = "EnvironmentCubeMapPipeline";
  44. childRequest.m_passName = "Child";
  45. PassConnection childInputConnection;
  46. childInputConnection.m_localSlot = "PipelineOutput";
  47. childInputConnection.m_attachmentRef.m_pass = "Parent";
  48. childInputConnection.m_attachmentRef.m_attachment = "Output";
  49. childRequest.m_connections.emplace_back(childInputConnection);
  50. PassSystemInterface* passSystem = PassSystemInterface::Get();
  51. m_childPass = passSystem->CreatePassFromRequest(&childRequest);
  52. AZ_Assert(m_childPass, "EnvironmentCubeMap child pass is invalid");
  53. // setup viewport
  54. m_viewportState.m_minX = 0;
  55. m_viewportState.m_minY = 0;
  56. m_viewportState.m_maxX = static_cast<float>(CubeMapFaceSize);
  57. m_viewportState.m_maxY = static_cast<float>(CubeMapFaceSize);
  58. // setup scissor
  59. m_scissorState.m_minX = 0;
  60. m_scissorState.m_minY = 0;
  61. m_scissorState.m_maxX = static_cast<int16_t>(CubeMapFaceSize);
  62. m_scissorState.m_maxY = static_cast<int16_t>(CubeMapFaceSize);
  63. // create view
  64. AZ::Name viewName(AZStd::string::format("%s_%s", childRequest.m_templateName.GetCStr(), childRequest.m_passName.GetCStr()));
  65. m_view = RPI::View::CreateView(viewName, RPI::View::UsageReflectiveCubeMap);
  66. AZ::Matrix3x4 viewTransform;
  67. const Vector3* basis = &CameraBasis[0][0];
  68. viewTransform.SetBasisAndTranslation(basis[0], basis[1], basis[2], m_position);
  69. m_view->SetCameraTransform(viewTransform);
  70. AZ::Matrix4x4 viewToClipMatrix;
  71. MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1.0f, 0.1f, 100.0f, true);
  72. m_view->SetViewToClipMatrix(viewToClipMatrix);
  73. }
  74. EnvironmentCubeMapPass::~EnvironmentCubeMapPass()
  75. {
  76. for (uint32_t i = 0; i < NumCubeMapFaces; ++i)
  77. {
  78. delete [] m_textureData[i];
  79. }
  80. }
  81. void EnvironmentCubeMapPass::SetDefaultView()
  82. {
  83. if (m_pipeline)
  84. {
  85. m_pipeline->SetDefaultView(m_view);
  86. }
  87. }
  88. void EnvironmentCubeMapPass::CreateChildPassesInternal()
  89. {
  90. AddChild(m_childPass);
  91. }
  92. void EnvironmentCubeMapPass::BuildInternal()
  93. {
  94. // create output image descriptor
  95. m_outputImageDesc = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::Color | RHI::ImageBindFlags::CopyRead, CubeMapFaceSize, CubeMapFaceSize, RHI::Format::R16G16B16A16_FLOAT);
  96. // create output PassAttachment
  97. m_passAttachment = aznew PassAttachment();
  98. m_passAttachment->m_name = "Output";
  99. AZ::Name attachmentPath(AZStd::string::format("%s.%s", GetPathName().GetCStr(), m_passAttachment->m_name.GetCStr()));
  100. m_passAttachment->m_path = attachmentPath;
  101. m_passAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient;
  102. m_passAttachment->m_descriptor = m_outputImageDesc;
  103. // create pass attachment binding
  104. PassAttachmentBinding outputAttachment;
  105. outputAttachment.m_name = "Output";
  106. outputAttachment.m_slotType = PassSlotType::InputOutput;
  107. outputAttachment.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget;
  108. outputAttachment.SetAttachment(m_passAttachment);
  109. AddAttachmentBinding(outputAttachment);
  110. ParentPass::BuildInternal();
  111. }
  112. void EnvironmentCubeMapPass::FrameBeginInternal(FramePrepareParams params)
  113. {
  114. params.m_scissorState = m_scissorState;
  115. params.m_viewportState = m_viewportState;
  116. RHI::FrameGraphAttachmentInterface attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase();
  117. attachmentDatabase.CreateTransientImage(RHI::TransientImageDescriptor(m_passAttachment->GetAttachmentId(), m_outputImageDesc));
  118. m_readBackLock.lock();
  119. if (!m_attachmentReadback || !m_readBackRequested)
  120. {
  121. // create the AttachmentReadback if this is the first time in FramePrepare, or we finished with the last readback
  122. // in which case we will free the previous one and allocate a new one
  123. m_attachmentReadback = AZStd::make_shared<AZ::RPI::AttachmentReadback>(AZ::RHI::ScopeId{ "EnvironmentCubeMapReadBack" });
  124. m_attachmentReadback->SetCallback(AZStd::bind(&EnvironmentCubeMapPass::AttachmentReadbackCallback, this, AZStd::placeholders::_1));
  125. }
  126. m_readBackLock.unlock();
  127. ParentPass::FrameBeginInternal(params);
  128. // Note: this needs to be after the call to ParentPass::FrameBeginInternal in order to setup the scopes correctly for readback
  129. m_attachmentReadback->FrameBegin(params);
  130. }
  131. void EnvironmentCubeMapPass::FrameEndInternal()
  132. {
  133. m_readBackLock.lock();
  134. if (m_renderFace < NumCubeMapFaces)
  135. {
  136. if (!m_readBackRequested)
  137. {
  138. // delay a number of frames before requesting the readback
  139. if (m_readBackDelayFrames < NumReadBackDelayFrames)
  140. {
  141. m_readBackDelayFrames++;
  142. }
  143. else
  144. {
  145. m_readBackRequested = true;
  146. AZStd::string readbackName = AZStd::string::format("%s_%s", m_passAttachment->GetAttachmentId().GetCStr(), GetName().GetCStr());
  147. m_attachmentReadback->ReadPassAttachment(m_passAttachment.get(), AZ::Name(readbackName));
  148. }
  149. }
  150. // set the appropriate render camera transform for the next frame
  151. AZ::Matrix3x4 viewTransform;
  152. const Vector3* basis = &CameraBasis[m_renderFace][0];
  153. viewTransform.SetBasisAndTranslation(basis[0], basis[1], basis[2], m_position);
  154. m_view->SetCameraTransform(viewTransform);
  155. m_pipeline->SetDefaultView(m_view);
  156. }
  157. m_readBackLock.unlock();
  158. ParentPass::FrameEndInternal();
  159. }
  160. void EnvironmentCubeMapPass::AttachmentReadbackCallback(const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
  161. {
  162. RHI::DeviceImageSubresourceLayout imageLayout =
  163. RHI::GetImageSubresourceLayout(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format);
  164. delete [] m_textureData[m_renderFace];
  165. // copy face texture data
  166. m_textureData[m_renderFace] = new uint8_t[imageLayout.m_bytesPerImage];
  167. uint32_t bytesRead = (uint32_t)readbackResult.m_dataBuffer->size();
  168. memcpy(m_textureData[m_renderFace], readbackResult.m_dataBuffer->data(), bytesRead);
  169. m_textureFormat = readbackResult.m_imageDescriptor.m_format;
  170. m_readBackLock.lock();
  171. {
  172. // move to the next face
  173. m_renderFace++;
  174. m_readBackRequested = false;
  175. m_readBackDelayFrames = 0;
  176. }
  177. m_readBackLock.unlock();
  178. }
  179. } // namespace RPI
  180. } // namespace AZ