SilhouetteFeatureProcessor.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 <Atom/RPI.Public/Pass/Pass.h>
  9. #include <Atom/RPI.Public/Pass/PassFilter.h>
  10. #include <Atom/RPI.Public/Pass/RasterPass.h>
  11. #include <Atom/RPI.Public/View.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
  15. #include <AzCore/Console/IConsole.h>
  16. #include <AzFramework/Entity/GameEntityContextBus.h>
  17. #include <AzFramework/Scene/Scene.h>
  18. #include <AzFramework/Scene/SceneSystemInterface.h>
  19. #include <Silhouette/SilhouetteFeatureProcessor.h>
  20. void OnSilhouetteActiveChanged(const bool& activate)
  21. {
  22. AzFramework::EntityContextId entityContextId;
  23. AzFramework::GameEntityContextRequestBus::BroadcastResult(
  24. entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
  25. if (auto scene = AZ::RPI::Scene::GetSceneForEntityContextId(entityContextId); scene != nullptr)
  26. {
  27. // avoid unnecessary enable/disable to avoid warning log spam
  28. auto featureProcessor = scene->GetFeatureProcessor<AZ::Render::SilhouetteFeatureProcessor>();
  29. if (featureProcessor)
  30. {
  31. featureProcessor->SetPassesEnabled(activate);
  32. }
  33. }
  34. }
  35. AZ_CVAR(
  36. bool,
  37. r_silhouette,
  38. true,
  39. &OnSilhouetteActiveChanged,
  40. AZ::ConsoleFunctorFlags::Null,
  41. "Controls if the silhouette rendering feature is active. 0 : Inactive, 1 : Active (default)");
  42. namespace AZ::Render
  43. {
  44. SilhouetteFeatureProcessor::SilhouetteFeatureProcessor() = default;
  45. SilhouetteFeatureProcessor::~SilhouetteFeatureProcessor() = default;
  46. void SilhouetteFeatureProcessor::Reflect(ReflectContext* context)
  47. {
  48. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  49. {
  50. serializeContext->Class<SilhouetteFeatureProcessor, FeatureProcessor>()->Version(0);
  51. }
  52. }
  53. void SilhouetteFeatureProcessor::Activate()
  54. {
  55. EnableSceneNotification();
  56. }
  57. void SilhouetteFeatureProcessor::Deactivate()
  58. {
  59. DisableSceneNotification();
  60. m_rasterPass = nullptr;
  61. m_compositePass = nullptr;
  62. }
  63. void SilhouetteFeatureProcessor::SetPassesEnabled(bool enabled)
  64. {
  65. if (m_compositePass && m_rasterPass)
  66. {
  67. m_compositePass->SetEnabled(enabled);
  68. m_rasterPass->SetEnabled(enabled);
  69. }
  70. }
  71. void SilhouetteFeatureProcessor::OnEndPrepareRender()
  72. {
  73. if (auto scene = GetParentScene(); scene != nullptr)
  74. {
  75. if (m_compositePass && m_rasterPass && m_rasterPass->GetRenderPipeline())
  76. {
  77. // Get DrawList from the dynamic draw interface and view
  78. AZStd::vector<RHI::DrawListView> drawLists = AZ::RPI::DynamicDrawInterface::Get()->GetDrawListsForPass(m_rasterPass);
  79. const AZStd::vector<AZ::RPI::ViewPtr>& views = m_rasterPass->GetRenderPipeline()->GetViews(m_rasterPass->GetPipelineViewTag());
  80. RHI::DrawListView viewDrawList;
  81. if (!views.empty())
  82. {
  83. const AZ::RPI::ViewPtr& view = views.front();
  84. viewDrawList = view->GetDrawList(m_rasterPass->GetDrawListTag());
  85. }
  86. if (drawLists.empty() && viewDrawList.empty())
  87. {
  88. m_compositePass->SetEnabled(false);
  89. }
  90. else
  91. {
  92. m_compositePass->SetEnabled(true);
  93. }
  94. }
  95. }
  96. }
  97. void SilhouetteFeatureProcessor::AddRenderPasses(RPI::RenderPipeline* renderPipeline)
  98. {
  99. // Early return if pass is already found in render pipeline or if the pipeline is not the default one.
  100. if (renderPipeline->GetViewType() != RPI::ViewType::Default)
  101. {
  102. return;
  103. }
  104. // the silhouette passes are already added in another render pipeline
  105. if (m_renderPipeline && m_renderPipeline != renderPipeline)
  106. {
  107. return;
  108. }
  109. UpdatePasses(renderPipeline);
  110. // if we already have valid render pass members then we don't need to dynamically
  111. // create them and add them to the pipeline
  112. if (m_compositePass && m_rasterPass)
  113. {
  114. return;
  115. }
  116. // unset the render pipeline until we add the passes successfully
  117. m_renderPipeline = nullptr;
  118. const auto mergeTemplateName = Name("SilhouettePassTemplate");
  119. const auto gatherTemplateName = Name("SilhouetteGatherPassTemplate");
  120. Name postProcessPassName = Name("PostProcessPass");
  121. if (renderPipeline->FindFirstPass(postProcessPassName) == nullptr)
  122. {
  123. AZ_Warning("SilhouetteFeatureProcessor", false, "Can't find %s in the render pipeline.", postProcessPassName.GetCStr());
  124. return;
  125. }
  126. Name forwardProcessPassName = Name("Forward");
  127. if (renderPipeline->FindFirstPass(forwardProcessPassName) == nullptr)
  128. {
  129. AZ_Warning("SilhouetteFeatureProcessor", false, "Can't find %s in the render pipeline.", forwardProcessPassName.GetCStr());
  130. return;
  131. }
  132. // Add the gather pass which draws all the silhouette objects into a render target
  133. // using depth and stencil to determine where to draw
  134. RPI::PassRequest gatherPassRequest;
  135. gatherPassRequest.m_passName = Name("SilhouetteGatherPass");
  136. gatherPassRequest.m_templateName = gatherTemplateName;
  137. gatherPassRequest.AddInputConnection(RPI::PassConnection{
  138. Name("DepthStencilInputOutput"), RPI::PassAttachmentRef{ forwardProcessPassName, Name("DepthStencilInputOutput") } });
  139. if (auto pass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(&gatherPassRequest); pass != nullptr)
  140. {
  141. m_rasterPass = static_cast<AZ::RPI::RasterPass*>(pass.get());
  142. renderPipeline->AddPassAfter(pass, forwardProcessPassName);
  143. }
  144. // Add the full screen silhouette pass which merges the silhouettes render target with
  145. // the framebuffer diffuse, and adds outlines to the silhouette shapes
  146. RPI::PassRequest compositePassRequest;
  147. compositePassRequest.m_passName = Name("SilhouettePass");
  148. compositePassRequest.m_templateName = mergeTemplateName;
  149. compositePassRequest.AddInputConnection(
  150. RPI::PassConnection{ Name("InputOutput"), RPI::PassAttachmentRef{ postProcessPassName, Name("Output") } });
  151. if (auto pass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(&compositePassRequest); pass != nullptr)
  152. {
  153. m_compositePass = pass.get();
  154. renderPipeline->AddPassAfter(pass, postProcessPassName);
  155. }
  156. // remember which render pipeline we added our passes to
  157. m_renderPipeline = renderPipeline;
  158. }
  159. void SilhouetteFeatureProcessor::OnRenderPipelineChanged(AZ::RPI::RenderPipeline* pipeline, AZ::RPI::SceneNotification::RenderPipelineChangeType changeType)
  160. {
  161. // Only need to recache silhouette passes if the pipeline had them
  162. if (pipeline == m_renderPipeline)
  163. {
  164. if (changeType == AZ::RPI::SceneNotification::RenderPipelineChangeType::Removed)
  165. {
  166. UpdatePasses(nullptr);
  167. }
  168. else
  169. {
  170. UpdatePasses(pipeline);
  171. }
  172. }
  173. }
  174. void SilhouetteFeatureProcessor::UpdatePasses(AZ::RPI::RenderPipeline* renderPipeline)
  175. {
  176. m_compositePass = nullptr;
  177. m_rasterPass = nullptr;
  178. if (renderPipeline == nullptr)
  179. {
  180. m_renderPipeline = nullptr;
  181. return;
  182. }
  183. const auto mergeTemplateName = Name("SilhouettePassTemplate");
  184. auto compositePassFilter = AZ::RPI::PassFilter::CreateWithTemplateName(mergeTemplateName, renderPipeline);
  185. if (auto foundPass = AZ::RPI::PassSystemInterface::Get()->FindFirstPass(compositePassFilter); foundPass)
  186. {
  187. m_compositePass = foundPass;
  188. }
  189. const auto gatherTemplateName = Name("SilhouetteGatherPassTemplate");
  190. auto gatherPassFilter = AZ::RPI::PassFilter::CreateWithTemplateName(gatherTemplateName, renderPipeline);
  191. if (auto foundPass = AZ::RPI::PassSystemInterface::Get()->FindFirstPass(gatherPassFilter); foundPass)
  192. {
  193. m_rasterPass = static_cast<AZ::RPI::RasterPass*>(foundPass);
  194. }
  195. // remember which render pipeline we found our passes on
  196. m_renderPipeline = (m_compositePass && m_rasterPass) ? renderPipeline : nullptr;
  197. }
  198. } // namespace AZ::Render