28
28
29
29
namespace AZ ::Render
30
30
{
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
+
31
64
void ProjectedShadowFeatureProcessor::Reflect (ReflectContext* context)
32
65
{
33
66
if (auto * serializeContext = azrtti_cast<SerializeContext*>(context))
@@ -631,14 +664,23 @@ namespace AZ::Render
631
664
}
632
665
}
633
666
}
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)
636
670
{
637
671
if (m_primaryProjectedShadowmapsPass != nullptr )
638
672
{
639
673
RPI::RenderPipeline* renderPipeline = m_primaryProjectedShadowmapsPass->GetRenderPipeline ();
640
674
if (renderPipeline)
641
675
{
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
+
642
684
auto & shadowProperties = m_shadowProperties.GetDataVector ();
643
685
for (ShadowProperty& shadowProperty : shadowProperties)
644
686
{
@@ -648,6 +690,12 @@ namespace AZ::Render
648
690
{
649
691
continue ;
650
692
}
693
+ auto lightPosition = shadowProperty.m_desc .m_transform .GetTranslation ();
694
+ if (cullShadowmapOutsideViewFrustum &&
695
+ !IsLightInsideAnyViewFrustum (mainViewFrustums, lightPosition, shadowProperty.m_desc .m_farPlaneDistance ))
696
+ {
697
+ continue ;
698
+ }
651
699
652
700
const RPI::PipelineViewTag& viewTag = shadowProperty.m_shadowmapPass ->GetPipelineViewTag ();
653
701
const RHI::DrawListMask drawListMask = renderPipeline->GetDrawListMask (viewTag);
0 commit comments