StarsFeatureProcessor.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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 <StarsFeatureProcessor.h>
  9. #include <Atom/RHI/DrawPacketBuilder.h>
  10. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  11. #include <Atom/RPI.Public/RenderPipeline.h>
  12. #include <Atom/RPI.Public/RPIUtils.h>
  13. #include <Atom/RPI.Public/Pass/PassFilter.h>
  14. #include <Atom/RPI.Public/Shader/Shader.h>
  15. #include <Atom/RPI.Public/Scene.h>
  16. #include <Atom/RPI.Public/View.h>
  17. #include <Atom/RPI.Public/ViewportContext.h>
  18. #include <Atom/RPI.Public/ViewportContextBus.h>
  19. namespace AZ::Render
  20. {
  21. void StarsFeatureProcessor::Reflect(ReflectContext* context)
  22. {
  23. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  24. {
  25. serializeContext
  26. ->Class<StarsFeatureProcessor, FeatureProcessor>()
  27. ->Version(1);
  28. }
  29. }
  30. void StarsFeatureProcessor::Activate()
  31. {
  32. const char* shaderFilePath = "Shaders/stars/stars.azshader";
  33. m_shader = RPI::LoadCriticalShader(shaderFilePath);
  34. if (!m_shader)
  35. {
  36. AZ_Error("StarsFeatureProcessor", false, "Failed to load required stars shader.");
  37. return;
  38. }
  39. Data::AssetBus::Handler::BusConnect(m_shader->GetAssetId());
  40. auto drawSrgLayout = m_shader->GetAsset()->GetDrawSrgLayout(m_shader->GetSupervariantIndex());
  41. AZ_Error("StarsFeatureProcessor", drawSrgLayout, "Failed to get the draw shader resource group layout for the stars shader.");
  42. if (drawSrgLayout)
  43. {
  44. m_drawSrg = RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), drawSrgLayout->GetName());
  45. }
  46. m_drawListTag = m_shader->GetDrawListTag();
  47. m_starParamsIndex.Reset();
  48. m_rotationIndex.Reset();
  49. auto viewportContextInterface = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  50. auto viewportContext = viewportContextInterface->GetViewportContextByScene(GetParentScene());
  51. m_viewportSize = viewportContext->GetViewportSize();
  52. EnableSceneNotification();
  53. RPI::ViewportContextIdNotificationBus::Handler::BusConnect(viewportContext->GetId());
  54. }
  55. void StarsFeatureProcessor::Deactivate()
  56. {
  57. Data::AssetBus::Handler::BusDisconnect(m_shader->GetAssetId());
  58. RPI::ViewportContextIdNotificationBus::Handler::BusDisconnect();
  59. DisableSceneNotification();
  60. m_shader = nullptr;
  61. }
  62. void StarsFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
  63. {
  64. AZ_PROFILE_SCOPE(RPI, "StarsFeatureProcessor: Simulate");
  65. if (m_updateShaderConstants)
  66. {
  67. m_updateShaderConstants = false;
  68. UpdateShaderConstants();
  69. }
  70. }
  71. void StarsFeatureProcessor::UpdateShaderConstants()
  72. {
  73. const float width = static_cast<float>(m_viewportSize.m_width);
  74. const float height = static_cast<float>(m_viewportSize.m_height);
  75. constexpr float minWidth = 1280.f;
  76. constexpr float minHeight = 720.f;
  77. const float size = m_radiusFactor * AZStd::min<float>(1.f, AZStd::min<float>(width / minWidth, height / minHeight));
  78. m_shaderConstants.m_scaleX = size / width;
  79. m_shaderConstants.m_scaleY = size / height;
  80. m_shaderConstants.m_scaledExposure = pow(2.f, m_exposure) * AZStd::min(1.f, size);
  81. if (m_drawSrg)
  82. {
  83. m_drawSrg->SetConstant(m_starParamsIndex, m_shaderConstants);
  84. m_drawSrg->SetConstant(m_rotationIndex, m_orientation);
  85. m_drawSrg->Compile();
  86. }
  87. }
  88. void StarsFeatureProcessor::UpdateDrawPacket()
  89. {
  90. if(m_meshPipelineState && m_drawSrg && m_meshStreamBufferViews[0].GetByteCount() != 0)
  91. {
  92. m_drawPacket = BuildDrawPacket(m_drawSrg, m_meshPipelineState, m_drawListTag, m_meshStreamBufferViews, m_numStarsVertices);
  93. }
  94. }
  95. void StarsFeatureProcessor::Render(const FeatureProcessor::RenderPacket& packet)
  96. {
  97. AZ_PROFILE_FUNCTION(AzRender);
  98. if (m_drawPacket)
  99. {
  100. for (auto& view : packet.m_views)
  101. {
  102. if (!view->HasDrawListTag(m_drawListTag))
  103. {
  104. continue;
  105. }
  106. constexpr float depth = 0.f;
  107. view->AddDrawPacket(m_drawPacket.get(), depth);
  108. }
  109. }
  110. }
  111. void StarsFeatureProcessor::SetStars(const AZStd::vector<StarVertex>& starVertexData)
  112. {
  113. const uint32_t elementCount = static_cast<uint32_t>(starVertexData.size());
  114. const uint32_t elementSize = sizeof(StarVertex);
  115. const uint32_t bufferSize = elementCount * elementSize; // bytecount
  116. m_starsMeshData = starVertexData;
  117. m_numStarsVertices = elementCount;
  118. if (!m_starsVertexBuffer)
  119. {
  120. RPI::CommonBufferDescriptor desc;
  121. desc.m_poolType = RPI::CommonBufferPoolType::StaticInputAssembly;
  122. desc.m_bufferName = "StarsMeshBuffer";
  123. desc.m_byteCount = bufferSize;
  124. desc.m_elementSize = elementSize;
  125. desc.m_bufferData = m_starsMeshData.data();
  126. m_starsVertexBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  127. }
  128. else
  129. {
  130. if (m_starsVertexBuffer->GetBufferSize() != bufferSize)
  131. {
  132. m_starsVertexBuffer->Resize(bufferSize);
  133. }
  134. m_starsVertexBuffer->UpdateData(m_starsMeshData.data(), bufferSize);
  135. }
  136. m_meshStreamBufferViews[0] = RHI::StreamBufferView(*m_starsVertexBuffer->GetRHIBuffer(), 0, bufferSize, elementSize);
  137. UpdateDrawPacket();
  138. }
  139. void StarsFeatureProcessor::SetExposure(float exposure)
  140. {
  141. m_exposure = exposure;
  142. m_updateShaderConstants = true;
  143. }
  144. void StarsFeatureProcessor::SetRadiusFactor(float radiusFactor)
  145. {
  146. m_radiusFactor = radiusFactor;
  147. m_updateShaderConstants = true;
  148. }
  149. void StarsFeatureProcessor::SetOrientation(AZ::Quaternion orientation)
  150. {
  151. m_orientation = AZ::Matrix3x3::CreateFromQuaternion(orientation);
  152. m_updateShaderConstants = true;
  153. }
  154. void StarsFeatureProcessor::SetTwinkleRate(float twinkleRate)
  155. {
  156. m_shaderConstants.m_twinkleRate = twinkleRate;
  157. m_updateShaderConstants = true;
  158. }
  159. void StarsFeatureProcessor::OnRenderPipelineAdded([[maybe_unused]] RPI::RenderPipelinePtr renderPipeline)
  160. {
  161. if(!m_meshPipelineState)
  162. {
  163. m_meshPipelineState = aznew RPI::PipelineStateForDraw;
  164. m_meshPipelineState->Init(m_shader);
  165. RHI::InputStreamLayoutBuilder layoutBuilder;
  166. layoutBuilder.AddBuffer()
  167. ->Channel("POSITION", RHI::Format::R32G32B32_FLOAT)
  168. ->Channel("COLOR", RHI::Format::R8G8B8A8_UNORM);
  169. layoutBuilder.SetTopology(RHI::PrimitiveTopology::TriangleList);
  170. auto inputStreamLayout = layoutBuilder.End();
  171. m_meshPipelineState->SetInputStreamLayout(inputStreamLayout);
  172. m_meshPipelineState->SetOutputFromScene(GetParentScene());
  173. m_meshPipelineState->Finalize();
  174. UpdateDrawPacket();
  175. UpdateBackgroundClearColor();
  176. }
  177. }
  178. void StarsFeatureProcessor::OnRenderPipelinePassesChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline)
  179. {
  180. if(m_meshPipelineState)
  181. {
  182. m_meshPipelineState->SetOutputFromScene(GetParentScene());
  183. m_meshPipelineState->Finalize();
  184. UpdateDrawPacket();
  185. UpdateBackgroundClearColor();
  186. }
  187. }
  188. void StarsFeatureProcessor::OnViewportSizeChanged(AzFramework::WindowSize size)
  189. {
  190. m_viewportSize = size;
  191. m_updateShaderConstants = true;
  192. }
  193. void StarsFeatureProcessor::OnAssetReloaded([[maybe_unused]] Data::Asset<Data::AssetData> asset)
  194. {
  195. UpdateDrawPacket();
  196. }
  197. void StarsFeatureProcessor::UpdateBackgroundClearColor()
  198. {
  199. // This function is only necessary for now because the default clear value
  200. // color is not black, and is set in various .pass files in places a user
  201. // is unlikely to find. Unfortunately, the viewport will revert to the
  202. // grey color when resizing momentarily.
  203. const RHI::ClearValue blackClearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  204. RPI::PassFilter passFilter;
  205. AZStd::string slot;
  206. auto setClearValue = [&](RPI::Pass* pass)-> RPI::PassFilterExecutionFlow
  207. {
  208. Name slotName = Name::FromStringLiteral(slot);
  209. if (auto binding = pass->FindAttachmentBinding(slotName))
  210. {
  211. binding->m_unifiedScopeDesc.m_loadStoreAction.m_clearValue = blackClearValue;
  212. }
  213. return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  214. };
  215. slot = "SpecularOutput";
  216. passFilter= RPI::PassFilter::CreateWithTemplateName(Name("ForwardPassTemplate"), GetParentScene());
  217. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, setClearValue);
  218. passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ForwardMSAAPassTemplate"), GetParentScene());
  219. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, setClearValue);
  220. slot = "ReflectionOutput";
  221. passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ReflectionGlobalFullscreenPassTemplate"), GetParentScene());
  222. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, setClearValue);
  223. }
  224. RHI::ConstPtr<RHI::DrawPacket> StarsFeatureProcessor::BuildDrawPacket(
  225. const Data::Instance<RPI::ShaderResourceGroup>& srg,
  226. const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
  227. const RHI::DrawListTag& drawListTag,
  228. const AZStd::span<const AZ::RHI::StreamBufferView>& streamBufferViews,
  229. uint32_t vertexCount)
  230. {
  231. RHI::DrawLinear drawLinear;
  232. drawLinear.m_vertexCount = vertexCount;
  233. drawLinear.m_vertexOffset = 0;
  234. drawLinear.m_instanceCount = 1;
  235. drawLinear.m_instanceOffset = 0;
  236. RHI::DrawPacketBuilder drawPacketBuilder;
  237. drawPacketBuilder.Begin(nullptr);
  238. drawPacketBuilder.SetDrawArguments(drawLinear);
  239. drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup());
  240. RHI::DrawPacketBuilder::DrawRequest drawRequest;
  241. drawRequest.m_listTag = drawListTag;
  242. drawRequest.m_pipelineState = pipelineState->GetRHIPipelineState();
  243. drawRequest.m_streamBufferViews = streamBufferViews;
  244. drawPacketBuilder.AddDrawItem(drawRequest);
  245. return drawPacketBuilder.End();
  246. }
  247. } // namespace AZ::Render