StarsFeatureProcessor.cpp 11 KB

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