Skip to content

Commit 86326ed

Browse files
Cull shadow views before drawing them
Signed-off-by: Mateusz Wasilewski <[email protected]>
1 parent 26baf4a commit 86326ed

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,39 @@
2828

2929
namespace AZ::Render
3030
{
31+
namespace
32+
{
33+
AZ_CVAR(
34+
bool,
35+
r_cullShadowmapOutsideViewFrustum,
36+
true,
37+
nullptr,
38+
AZ::ConsoleFunctorFlags::DontReplicate | AZ::ConsoleFunctorFlags::DontDuplicate,
39+
"If set, enables filtering of shadow maps that are outside of the view frustum.");
40+
41+
bool IsShadowmapCullingEnabled()
42+
{
43+
bool cullShadowmapOutsideViewFrustum = true;
44+
if (auto* console = AZ::Interface<AZ::IConsole>::Get())
45+
{
46+
console->GetCvarValue("r_cullShadowmapOutsideViewFrustum", cullShadowmapOutsideViewFrustum);
47+
}
48+
return cullShadowmapOutsideViewFrustum;
49+
}
50+
51+
bool IsLightInsideAnyViewFrustum(AZStd::span<AZ::Frustum> viewFrustums, const AZ::Vector3& lightPosition, float attenuationRadius)
52+
{
53+
return std::any_of(
54+
viewFrustums.begin(),
55+
viewFrustums.end(),
56+
[lightPosition, attenuationRadius](const AZ::Frustum& viewFrustum)
57+
{
58+
return viewFrustum.IntersectSphere(lightPosition, attenuationRadius) != AZ::IntersectResult::Exterior;
59+
});
60+
}
61+
62+
} // namespace
63+
3164
void ProjectedShadowFeatureProcessor::Reflect(ReflectContext* context)
3265
{
3366
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
@@ -631,23 +664,41 @@ namespace AZ::Render
631664
}
632665
}
633666
}
634-
635-
void ProjectedShadowFeatureProcessor::PrepareViews(const PrepareViewsPacket&, AZStd::vector<AZStd::pair<RPI::PipelineViewTag, RPI::ViewPtr>>& outViews)
667+
668+
void ProjectedShadowFeatureProcessor::PrepareViews(
669+
const PrepareViewsPacket& prepareViewsPacket, AZStd::vector<AZStd::pair<RPI::PipelineViewTag, RPI::ViewPtr>>& outViews)
636670
{
637671
if (m_primaryProjectedShadowmapsPass != nullptr)
638672
{
639673
RPI::RenderPipeline* renderPipeline = m_primaryProjectedShadowmapsPass->GetRenderPipeline();
640674
if (renderPipeline)
641675
{
676+
AZStd::vector<AZ::Frustum> mainViewFrustums;
677+
for (const auto& [view, viewTag] : prepareViewsPacket.m_persistentViews)
678+
{
679+
AZ::Frustum viewFrustum = AZ::Frustum::CreateFromMatrixColumnMajor(view->GetWorldToClipMatrix());
680+
mainViewFrustums.push_back(viewFrustum);
681+
}
682+
bool cullShadowmapOutsideViewFrustum = IsShadowmapCullingEnabled();
683+
642684
auto& shadowProperties = m_shadowProperties.GetDataVector();
643685
for (ShadowProperty& shadowProperty : shadowProperties)
644686
{
645687
uint16_t shadowIndex = shadowProperty.m_shadowId.GetIndex();
646688
const FilterParameter& filterData = m_shadowData.GetElement<FilterParamIndex>(shadowIndex);
647-
if (filterData.m_shadowmapSize == aznumeric_cast<uint32_t>(ShadowmapSize::None))
689+
bool needsRender = filterData.m_shadowmapSize != aznumeric_cast<uint32_t>(ShadowmapSize::None);
690+
if (!needsRender)
691+
{
692+
continue;
693+
}
694+
auto lightPosition = shadowProperty.m_desc.m_transform.GetTranslation();
695+
if (cullShadowmapOutsideViewFrustum &&
696+
!IsLightInsideAnyViewFrustum(mainViewFrustums, lightPosition, shadowProperty.m_desc.m_farPlaneDistance))
648697
{
698+
shadowProperty.m_shadowmapPass->SetEnabled(false);
649699
continue;
650700
}
701+
shadowProperty.m_shadowmapPass->SetEnabled(true);
651702

652703
const RPI::PipelineViewTag& viewTag = shadowProperty.m_shadowmapPass->GetPipelineViewTag();
653704
const RHI::DrawListMask drawListMask = renderPipeline->GetDrawListMask(viewTag);

Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ namespace AZ::Render
3939
void Activate() override;
4040
void Deactivate() override;
4141
void Simulate(const SimulatePacket& packet) override;
42-
void PrepareViews(const PrepareViewsPacket&, AZStd::vector<AZStd::pair<RPI::PipelineViewTag, RPI::ViewPtr>>&) override;
42+
void PrepareViews(
43+
const PrepareViewsPacket& prepareViewsPacket, AZStd::vector<AZStd::pair<RPI::PipelineViewTag, RPI::ViewPtr>>&) override;
4344
void Render(const RenderPacket& packet) override;
4445

4546
// ProjectedShadowFeatureProcessorInterface overrides ...

Gems/Atom/RPI/Code/Include/Atom/RPI.Public/FeatureProcessor.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ namespace AZ
4848
friend class Scene;
4949
public:
5050

51-
// [GFX TODO]: now these structure are empty, but we will clean up them later when we are sure we won't have any members in them.
51+
public:
5252
struct PrepareViewsPacket
5353
{
54+
AZStd::map<ViewPtr, RHI::DrawListMask> m_persistentViews;
5455
};
5556

5657
struct SimulatePacket
@@ -105,7 +106,8 @@ namespace AZ
105106
//! views (transient views) are views that must be rendered only to correctly render
106107
//! the main views. This function is called per frame and it happens on main thread.
107108
//! Support views should be added to outViews with their associated pipeline view tags.
108-
virtual void PrepareViews(const PrepareViewsPacket&, AZStd::vector<AZStd::pair<PipelineViewTag, ViewPtr>>& /* outViews*/) {}
109+
virtual void PrepareViews(
110+
const PrepareViewsPacket& /*prepareViewPacket*/, AZStd::vector<AZStd::pair<PipelineViewTag, ViewPtr>>& /*outViews*/) {}
109111

110112
//! The feature processor should perform any internal simulation at this point - For
111113
//! instance, updating a particle system or animation. Not every feature processor

Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ namespace AZ
786786

787787
// Collect transient views from each feature processor
788788
FeatureProcessor::PrepareViewsPacket prepareViewPacket;
789+
prepareViewPacket.m_persistentViews = persistentViews;
789790
AZStd::vector<AZStd::pair<PipelineViewTag, ViewPtr>> transientViews;
790791
for (auto& fp : m_featureProcessors)
791792
{

0 commit comments

Comments
 (0)