NewDepthOfFieldPasses.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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/Console/IConsole.h>
  9. #include <AzCore/Math/MathUtils.h>
  10. #include <PostProcess/PostProcessFeatureProcessor.h>
  11. #include <PostProcess/DepthOfField/DepthOfFieldSettings.h>
  12. #include <PostProcessing/NewDepthOfFieldPasses.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RPI.Public/Scene.h>
  15. #include <Atom/RPI.Public/View.h>
  16. namespace AZ
  17. {
  18. namespace Render
  19. {
  20. AZ_CVAR(bool, r_enableDOF, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable depth of field effect support");
  21. // Must match the struct in NewDepthOfFieldCommon.azsli
  22. struct NewDepthOfFieldConstants
  23. {
  24. static constexpr uint32_t numberOfLoops = 3;
  25. static constexpr float loopCounts[] = { 8.0f, 16.0f, 24.0f };
  26. AZStd::array<float[4], 60> m_samplePositions; // XY are sample positions (normalized so max lenght is 1)
  27. // Z is the length of XY (0 - 1)
  28. // W is unused
  29. };
  30. // --- Depth of Field Parent Pass ---
  31. RPI::Ptr<NewDepthOfFieldParentPass> NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor)
  32. {
  33. RPI::Ptr<NewDepthOfFieldParentPass> pass = aznew NewDepthOfFieldParentPass(descriptor);
  34. return AZStd::move(pass);
  35. }
  36. NewDepthOfFieldParentPass::NewDepthOfFieldParentPass(const RPI::PassDescriptor& descriptor)
  37. : RPI::ParentPass(descriptor)
  38. { }
  39. bool NewDepthOfFieldParentPass::IsEnabled() const
  40. {
  41. if (!r_enableDOF)
  42. {
  43. return false;
  44. }
  45. if (!ParentPass::IsEnabled())
  46. {
  47. return false;
  48. }
  49. RPI::Scene* scene = GetScene();
  50. if (!scene)
  51. {
  52. return false;
  53. }
  54. PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor<PostProcessFeatureProcessor>();
  55. AZ::RPI::ViewPtr view = GetRenderPipeline()->GetFirstView(GetPipelineViewTag());
  56. if (!fp)
  57. {
  58. return false;
  59. }
  60. PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
  61. if (!postProcessSettings)
  62. {
  63. return false;
  64. }
  65. DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings();
  66. return (dofSettings != nullptr) && dofSettings->GetEnabled();
  67. }
  68. void NewDepthOfFieldParentPass::FrameBeginInternal(FramePrepareParams params)
  69. {
  70. RPI::Scene* scene = GetScene();
  71. PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor<PostProcessFeatureProcessor>();
  72. AZ::RPI::ViewPtr view = GetRenderPipeline()->GetFirstView(GetPipelineViewTag());
  73. if (fp)
  74. {
  75. PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
  76. if (postProcessSettings)
  77. {
  78. DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings();
  79. if (dofSettings)
  80. {
  81. dofSettings->SetValuesToViewSrg(view->GetShaderResourceGroup());
  82. }
  83. }
  84. }
  85. ParentPass::FrameBeginInternal(params);
  86. }
  87. // --- Tile Reduce Pass ---
  88. RPI::Ptr<NewDepthOfFieldTileReducePass> NewDepthOfFieldTileReducePass::Create(const RPI::PassDescriptor& descriptor)
  89. {
  90. RPI::Ptr<NewDepthOfFieldTileReducePass> pass = aznew NewDepthOfFieldTileReducePass(descriptor);
  91. return AZStd::move(pass);
  92. }
  93. NewDepthOfFieldTileReducePass::NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor)
  94. : RPI::ComputePass(descriptor)
  95. {
  96. // Though this is a fullscreen pass, the shader computes 16x16 tiles with groups of 8x8 threads,
  97. // each thread outputting to a single pixel in the tiled min/max texture
  98. m_fullscreenDispatch = false;
  99. }
  100. void NewDepthOfFieldTileReducePass::FrameBeginInternal(FramePrepareParams params)
  101. {
  102. AZ_Assert(GetOutputCount() > 0, "NewDepthOfFieldTileReducePass: No output bindings!");
  103. RPI::PassAttachment* outputAttachment = GetOutputBinding(0).GetAttachment().get();
  104. AZ_Assert(outputAttachment != nullptr, "NewDepthOfFieldTileReducePass: Output binding has no attachment!");
  105. RHI::Size outputSize = outputAttachment->m_descriptor.m_image.m_size;
  106. // The algorithm outputs the min/max CoC values from a 16x16 region using 8x8 threads
  107. u32 targetThreadCountX = outputSize.m_width * 8;
  108. u32 targetThreadCountY = outputSize.m_height * 8;
  109. SetTargetThreadCounts(targetThreadCountX, targetThreadCountY, 1);
  110. RPI::ComputePass::FrameBeginInternal(params);
  111. }
  112. // --- Filter Pass ---
  113. RPI::Ptr<NewDepthOfFieldFilterPass> NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor)
  114. {
  115. RPI::Ptr<NewDepthOfFieldFilterPass> pass = aznew NewDepthOfFieldFilterPass(descriptor);
  116. return AZStd::move(pass);
  117. }
  118. NewDepthOfFieldFilterPass::NewDepthOfFieldFilterPass(const RPI::PassDescriptor& descriptor)
  119. : RPI::FullscreenTrianglePass(descriptor)
  120. { }
  121. void NewDepthOfFieldFilterPass::FrameBeginInternal(FramePrepareParams params)
  122. {
  123. NewDepthOfFieldConstants dofConstants;
  124. uint32_t sampleIndex = 0;
  125. // Calculate all the offset positions
  126. for (uint32_t loop = 0; loop < NewDepthOfFieldConstants::numberOfLoops; ++loop)
  127. {
  128. float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops);
  129. float loopCount = NewDepthOfFieldConstants::loopCounts[loop];
  130. float angleStep = Constants::TwoPi / loopCount;
  131. // Every other loop slightly rotate sample ring so they don't line up
  132. float angle = (loop & 1) ? (angleStep * 0.5f) : 0;
  133. for (float i = 0.0f; i < loopCount; ++i)
  134. {
  135. Vector2 pos = Vector2::CreateFromAngle(angle);
  136. pos = pos * radius;
  137. dofConstants.m_samplePositions[sampleIndex][0] = pos.GetX();
  138. dofConstants.m_samplePositions[sampleIndex][1] = pos.GetY();
  139. dofConstants.m_samplePositions[sampleIndex][2] = radius;
  140. dofConstants.m_samplePositions[sampleIndex][3] = 0.0f;
  141. ++sampleIndex;
  142. angle += angleStep;
  143. }
  144. }
  145. m_shaderResourceGroup->SetConstant(m_constantsIndex, dofConstants);
  146. RPI::FullscreenTrianglePass::FrameBeginInternal(params);
  147. }
  148. } // namespace Render
  149. } // namespace AZ