Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp
2025-05-18 13:04:45 +08:00

729 lines
25 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
CompositionLighting.cpp: The center for all deferred lighting activities.
=============================================================================*/
#include "CompositionLighting/CompositionLighting.h"
#include "ScenePrivate.h"
#include "SceneProxies/SkyLightSceneProxy.h"
#include "PostProcess/PostProcessing.h"
#include "CompositionLighting/PostProcessAmbientOcclusion.h"
#include "CompositionLighting/PostProcessDeferredDecals.h"
#include "PostProcess/PostProcessSubsurface.h"
#include "DecalRenderingShared.h"
#include "VisualizeTexture.h"
#include "RayTracing/RaytracingOptions.h"
#include "SceneTextureParameters.h"
#include "RenderGraphUtils.h"
DECLARE_GPU_STAT_NAMED(CompositionBeforeBasePass, TEXT("Composition BeforeBasePass") );
DECLARE_GPU_STAT_NAMED(CompositionPreLighting, TEXT("Composition PreLighting") );
DECLARE_GPU_STAT_NAMED(CompositionPostLighting, TEXT("Composition PostLighting") );
static TAutoConsoleVariable<int32> CVarSSAOSmoothPass(
TEXT("r.AmbientOcclusion.Compute.Smooth"),
1,
TEXT("Whether to smooth SSAO output when TAA is disabled"),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarGTAODownsample(
TEXT("r.GTAO.Downsample"),
0,
TEXT("Perform GTAO at Halfres \n ")
TEXT("0: Off \n ")
TEXT("1: On (default)\n "),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarGTAOTemporalFilter(
TEXT("r.GTAO.TemporalFilter"),
1,
TEXT("Enable Temporal Filter for GTAO \n ")
TEXT("0: Off \n ")
TEXT("1: On (default)\n "),
ECVF_RenderThreadSafe | ECVF_Scalability);
static TAutoConsoleVariable<int32> CVarGTAOSpatialFilter(
TEXT("r.GTAO.SpatialFilter"),
1,
TEXT("Enable Spatial Filter for GTAO \n ")
TEXT("0: Off \n ")
TEXT("1: On (default)\n "),
ECVF_RenderThreadSafe | ECVF_Scalability);
bool IsAmbientCubemapPassRequired(const FSceneView& View)
{
return View.FinalPostProcessSettings.ContributingCubemaps.Num() != 0 && IsUsingGBuffers(View.GetShaderPlatform());
}
static bool IsReflectionEnvironmentActive(const FSceneView& View)
{
FScene* Scene = (FScene*)View.Family->Scene;
// LPV & Screenspace Reflections : Reflection Environment active if either LPV (assumed true if this was called), Reflection Captures or SSR active
bool IsReflectingEnvironment = View.Family->EngineShowFlags.ReflectionEnvironment;
bool HasReflectionCaptures = (Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num() > 0);
bool HasSSR = View.Family->EngineShowFlags.ScreenSpaceReflections;
return (Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5 && IsReflectingEnvironment && (HasReflectionCaptures || HasSSR) && !IsForwardShadingEnabled(View.GetShaderPlatform()));
}
static bool IsSkylightActive(const FViewInfo& View)
{
FScene* Scene = (FScene*)View.Family->Scene;
return Scene->SkyLight
&& Scene->SkyLight->ProcessedTexture
&& View.Family->EngineShowFlags.SkyLighting;
}
bool ShouldRenderScreenSpaceAmbientOcclusion(const FViewInfo& View, bool bLumenWantsSSAO)
{
bool bEnabled = true;
bEnabled = View.FinalPostProcessSettings.AmbientOcclusionIntensity > 0
&& View.Family->EngineShowFlags.Lighting
&& View.FinalPostProcessSettings.AmbientOcclusionRadius >= 0.1f
&& !View.Family->UseDebugViewPS()
&& (FSSAOHelper::IsBasePassAmbientOcclusionRequired(View) || IsAmbientCubemapPassRequired(View) || IsReflectionEnvironmentActive(View) || IsSkylightActive(View) || IsForwardShadingEnabled(View.GetShaderPlatform()) || View.Family->EngineShowFlags.VisualizeBuffer || bLumenWantsSSAO);
bEnabled &= !ShouldRenderRayTracingAmbientOcclusion(View);
return bEnabled;
}
static ESSAOType GetDownscaleSSAOType(const FViewInfo& View)
{
return FSSAOHelper::IsAmbientOcclusionCompute(View.GetFeatureLevel()) ? ESSAOType::ECS : ESSAOType::EPS;
}
static ESSAOType GetFullscreenSSAOType(const FViewInfo& View, uint32 Levels)
{
if (FSSAOHelper::IsAmbientOcclusionCompute(View.GetFeatureLevel()))
{
if (FSSAOHelper::IsAmbientOcclusionAsyncCompute(View, Levels))
{
return ESSAOType::EAsyncCS;
}
return ESSAOType::ECS;
}
return ESSAOType::EPS;
}
static FSSAOCommonParameters GetSSAOCommonParameters(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
uint32 Levels,
bool bAllowGBufferRead)
{
const FSceneTextureParameters SceneTextureParameters = GetSceneTextureParameters(GraphBuilder, SceneTexturesUniformBuffer);
FSSAOCommonParameters CommonParameters;
CommonParameters.SceneTexturesUniformBuffer = SceneTexturesUniformBuffer;
CommonParameters.SceneTexturesViewport = FScreenPassTextureViewport(SceneTextureParameters.SceneDepthTexture, View.ViewRect);
CommonParameters.GBufferA = bAllowGBufferRead ? FScreenPassTexture(SceneTextureParameters.GBufferATexture, View.ViewRect) : FScreenPassTexture();
CommonParameters.SceneDepth = FScreenPassTexture(SceneTextureParameters.SceneDepthTexture, View.ViewRect);
CommonParameters.Levels = Levels;
CommonParameters.ShaderQuality = FSSAOHelper::GetAmbientOcclusionShaderLevel(View);
CommonParameters.DownscaleType = GetDownscaleSSAOType(View);
CommonParameters.FullscreenType = GetFullscreenSSAOType(View, Levels);
// If there is no temporal upsampling, we need a smooth pass to get rid of the grid pattern.
// Pixel shader version has relatively smooth result so no need to do extra work.
CommonParameters.bNeedSmoothingPass = CommonParameters.FullscreenType != ESSAOType::EPS && !IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod) && CVarSSAOSmoothPass.GetValueOnRenderThread();
return CommonParameters;
}
FGTAOCommonParameters GetGTAOCommonParameters(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
EGTAOType GTAOType
)
{
const FSceneTextureParameters SceneTextureParameters = GetSceneTextureParameters(GraphBuilder, SceneTexturesUniformBuffer);
FGTAOCommonParameters CommonParameters;
CommonParameters.SceneTexturesUniformBuffer = SceneTexturesUniformBuffer;
CommonParameters.SceneTexturesViewport = FScreenPassTextureViewport(SceneTextureParameters.SceneDepthTexture, View.ViewRect);
CommonParameters.SceneDepth = FScreenPassTexture(SceneTextureParameters.SceneDepthTexture, View.ViewRect);
CommonParameters.SceneVelocity = FScreenPassTexture(SceneTextureParameters.GBufferVelocityTexture, View.ViewRect);
CommonParameters.ShaderQuality = FSSAOHelper::GetAmbientOcclusionShaderLevel(View);
CommonParameters.DownscaleFactor = CVarGTAODownsample.GetValueOnRenderThread() > 0 ? 2 : 1;
CommonParameters.GTAOType = GTAOType;
CommonParameters.DownsampledViewRect = GetDownscaledRect(View.ViewRect, CommonParameters.DownscaleFactor);
return CommonParameters;
}
// Async Passes of the GTAO.
// This can either just be the Horizon search if GBuffer Normals are needed or it can be
// Combined Horizon search and Integrate followed by the Spatial filter if no normals are needed
static FGTAOHorizonSearchOutputs AddPostProcessingGTAOAsyncPasses(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FGTAOCommonParameters& CommonParameters,
FScreenPassRenderTarget GTAOHorizons
)
{
check(CommonParameters.GTAOType == EGTAOType::EAsyncHorizonSearch || CommonParameters.GTAOType == EGTAOType::EAsyncCombinedSpatial);
const bool bSpatialPass = (CVarGTAOSpatialFilter.GetValueOnRenderThread() == 1);
FGTAOHorizonSearchOutputs HorizonSearchOutputs;
if (CommonParameters.GTAOType == EGTAOType::EAsyncHorizonSearch)
{
HorizonSearchOutputs =
AddGTAOHorizonSearchPass(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth,
GTAOHorizons);
}
else
{
HorizonSearchOutputs =
AddGTAOHorizonSearchIntegratePass(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth);
if (bSpatialPass)
{
FScreenPassTexture SpatialOutput =
AddGTAOSpatialFilter(
GraphBuilder,
View,
CommonParameters,
HorizonSearchOutputs.Color,
CommonParameters.SceneDepth,
GTAOHorizons);
}
}
return MoveTemp(HorizonSearchOutputs);
}
// The whole GTAO stack is run on the Gfx Pipe
static FScreenPassTexture AddPostProcessingGTAOAllPasses(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FGTAOCommonParameters& CommonParameters,
FScreenPassRenderTarget FinalTarget)
{
FSceneViewState* ViewState = View.ViewState;
const bool bSpatialPass = (CVarGTAOSpatialFilter.GetValueOnRenderThread() == 1);
const bool bTemporalPass = (ViewState && CVarGTAOTemporalFilter.GetValueOnRenderThread() == 1);
{
FGTAOHorizonSearchOutputs HorizonSearchOutputs =
AddGTAOHorizonSearchIntegratePass(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth);
FScreenPassTexture CurrentOutput = HorizonSearchOutputs.Color;
if (bSpatialPass)
{
CurrentOutput =
AddGTAOSpatialFilter(
GraphBuilder,
View,
CommonParameters,
HorizonSearchOutputs.Color,
CommonParameters.SceneDepth);
}
if (bTemporalPass)
{
const FGTAOTAAHistory& InputHistory = View.PrevViewInfo.GTAOHistory;
FGTAOTAAHistory* OutputHistory = &View.ViewState->PrevFrameViewInfo.GTAOHistory;
FScreenPassTextureViewport HistoryViewport(InputHistory.ReferenceBufferSize, InputHistory.ViewportRect);
FScreenPassTexture HistoryColor;
if (InputHistory.IsValid())
{
HistoryColor = FScreenPassTexture(GraphBuilder.RegisterExternalTexture(InputHistory.RT, TEXT("GTAOHistoryColor")), HistoryViewport.Rect);
}
else
{
HistoryColor = FScreenPassTexture(GraphBuilder.RegisterExternalTexture(GSystemTextures.WhiteDummy, TEXT("GTAODummyTexture")));
HistoryViewport = FScreenPassTextureViewport(HistoryColor);
}
FGTAOTemporalOutputs TemporalOutputs =
AddGTAOTemporalPass(
GraphBuilder,
View,
CommonParameters,
CurrentOutput,
CommonParameters.SceneDepth,
CommonParameters.SceneVelocity,
HistoryColor,
HistoryViewport);
OutputHistory->SafeRelease();
GraphBuilder.QueueTextureExtraction(TemporalOutputs.OutputAO.Texture, &OutputHistory->RT);
OutputHistory->ReferenceBufferSize = TemporalOutputs.TargetExtent;
OutputHistory->ViewportRect = TemporalOutputs.ViewportRect;
CurrentOutput = TemporalOutputs.OutputAO;
}
FScreenPassTexture FinalOutput = CurrentOutput;
// TODO: Can't switch outputs since it's an external texture. Won't be a problem when we're fully over to RDG.
//if (DownsampleFactor > 1)
{
FinalOutput =
AddGTAOUpsamplePass(
GraphBuilder,
View,
CommonParameters,
CurrentOutput,
CommonParameters.SceneDepth,
FinalTarget);
}
}
return MoveTemp(FinalTarget);
}
// These are the passes run after Async where some are run before on the Async pipe
static FScreenPassTexture AddPostProcessingGTAOPostAsync(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FGTAOCommonParameters& CommonParameters,
FScreenPassTexture GTAOHorizons,
FScreenPassRenderTarget FinalTarget)
{
FSceneViewState* ViewState = View.ViewState;
const bool bSpatialPass = (CVarGTAOSpatialFilter.GetValueOnRenderThread() == 1);
const bool bTemporalPass = (ViewState && CVarGTAOTemporalFilter.GetValueOnRenderThread() == 1);
{
FScreenPassTexture CurrentOutput;
if (CommonParameters.GTAOType == EGTAOType::EAsyncHorizonSearch)
{
CurrentOutput =
AddGTAOInnerIntegratePass(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth,
GTAOHorizons);
if (bSpatialPass)
{
CurrentOutput =
AddGTAOSpatialFilter(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth,
CurrentOutput);
}
}
else
{
// If the Spatial Filter is running as part of the async then we'll render to the R channel of the horizons texture so it can be read in as part of the temporal
CurrentOutput = GTAOHorizons;
}
if (bTemporalPass)
{
const FGTAOTAAHistory& InputHistory = View.PrevViewInfo.GTAOHistory;
FGTAOTAAHistory* OutputHistory = &ViewState->PrevFrameViewInfo.GTAOHistory;
FScreenPassTextureViewport HistoryViewport(InputHistory.ReferenceBufferSize, InputHistory.ViewportRect);
FScreenPassTexture HistoryColor;
if (InputHistory.IsValid())
{
HistoryColor = FScreenPassTexture(GraphBuilder.RegisterExternalTexture(InputHistory.RT, TEXT("GTAOHistoryColor")), HistoryViewport.Rect);
}
else
{
HistoryColor = FScreenPassTexture(GraphBuilder.RegisterExternalTexture(GSystemTextures.WhiteDummy, TEXT("GTAODummyTexture")));
HistoryViewport = FScreenPassTextureViewport(HistoryColor);
}
FGTAOTemporalOutputs TemporalOutputs =
AddGTAOTemporalPass(
GraphBuilder,
View,
CommonParameters,
CurrentOutput,
CommonParameters.SceneDepth,
CommonParameters.SceneVelocity,
HistoryColor,
HistoryViewport);
OutputHistory->SafeRelease();
GraphBuilder.QueueTextureExtraction(TemporalOutputs.OutputAO.Texture, &OutputHistory->RT);
OutputHistory->ReferenceBufferSize = TemporalOutputs.TargetExtent;
OutputHistory->ViewportRect = TemporalOutputs.ViewportRect;
CurrentOutput = TemporalOutputs.OutputAO;
}
FScreenPassTexture FinalOutput = CurrentOutput;
// TODO: Can't switch outputs since it's an external texture. Won't be a problem when we're fully over to RDG.
//if (DownsampleFactor > 1)
{
FinalOutput =
AddGTAOUpsamplePass(
GraphBuilder,
View,
CommonParameters,
CurrentOutput,
CommonParameters.SceneDepth,
FinalTarget);
}
}
return MoveTemp(FinalTarget);
}
// @param Levels 0..3, how many different resolution levels we want to render
static FScreenPassTexture AddPostProcessingAmbientOcclusion(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FSSAOCommonParameters& CommonParameters,
FScreenPassRenderTarget FinalTarget)
{
check(CommonParameters.Levels >= 0 && CommonParameters.Levels <= 3);
FScreenPassTexture AmbientOcclusionInMip1;
FScreenPassTexture AmbientOcclusionPassMip1;
if (CommonParameters.Levels >= 2)
{
AmbientOcclusionInMip1 =
AddAmbientOcclusionSetupPass(
GraphBuilder,
View,
CommonParameters,
CommonParameters.SceneDepth);
FScreenPassTexture AmbientOcclusionPassMip2;
if (CommonParameters.Levels >= 3)
{
FScreenPassTexture AmbientOcclusionInMip2 =
AddAmbientOcclusionSetupPass(
GraphBuilder,
View,
CommonParameters,
AmbientOcclusionInMip1);
AmbientOcclusionPassMip2 =
AddAmbientOcclusionStepPass(
GraphBuilder,
View,
CommonParameters,
AmbientOcclusionInMip2,
AmbientOcclusionInMip2,
FScreenPassTexture());
}
AmbientOcclusionPassMip1 =
AddAmbientOcclusionStepPass(
GraphBuilder,
View,
CommonParameters,
AmbientOcclusionInMip1,
AmbientOcclusionInMip1,
AmbientOcclusionPassMip2);
}
FScreenPassTexture SetupTexture = CommonParameters.GBufferA;
if (Substrate::IsSubstrateEnabled())
{
// For Substrate, we invalidate the setup texture for the final pass:
// - We do not need GBufferA, the Substrate TopLayer texture will fill in for that.
// - Setting it to nullptr will make the AddAmbientOcclusionPass use a valid viewport from SceneTextures.
SetupTexture.Texture = nullptr;
}
FScreenPassTexture FinalOutput =
AddAmbientOcclusionFinalPass(
GraphBuilder,
View,
CommonParameters,
SetupTexture,
AmbientOcclusionInMip1,
AmbientOcclusionPassMip1,
FinalTarget);
return FinalOutput;
}
FCompositionLighting::FCompositionLighting(FDecalVisibilityTaskData* InDecalVisibility, TArrayView<FViewInfo> InViews, const FSceneTextures& InSceneTextures, TUniqueFunction<bool(int32)> RequestSSAOFunction)
: Views(InViews)
, ViewFamily(*InViews[0].Family)
, SceneTextures(InSceneTextures)
, DecalVisibility(InDecalVisibility)
{
ViewAOConfigs.SetNum(Views.Num());
for (int32 Index = 0; Index < Views.Num(); ++Index)
{
ViewAOConfigs[Index].bRequested = RequestSSAOFunction(Index);
}
}
FCompositionLighting::~FCompositionLighting()
{
if (DecalVisibility)
{
DecalVisibility->Finish();
}
}
void FCompositionLighting::TryInit()
{
if (bInitialized)
{
return;
}
const bool bForwardShading = IsForwardShadingEnabled(SceneTextures.Config.ShaderPlatform);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
FAOConfig& ViewConfig = ViewAOConfigs[ViewIndex];
if (!ViewConfig.bRequested)
{
continue;
}
ViewConfig.Levels = FSSAOHelper::ComputeAmbientOcclusionPassCount(View);
if (!bForwardShading)
{
ViewConfig.GTAOType = FSSAOHelper::GetGTAOPassType(View, ViewConfig.Levels);
}
if (ViewConfig.GTAOType == EGTAOType::EOff && ViewConfig.Levels > 0)
{
ViewConfig.bSSAOAsync = FSSAOHelper::IsAmbientOcclusionAsyncCompute(View, ViewConfig.Levels);
ViewConfig.SSAOLocation = IsHZBValid(View, EHZBType::FurthestHZB) && (ViewConfig.bSSAOAsync || bForwardShading)
? ESSAOLocation::BeforeBasePass
: ESSAOLocation::AfterBasePass;
}
}
bInitialized = true;
}
void FCompositionLighting::ProcessBeforeBasePass(FRDGBuilder& GraphBuilder, FDBufferTextures& DBufferTextures, FInstanceCullingManager& InstanceCullingManager, const FSubstrateSceneData& SubstrateSceneData)
{
if (HasRayTracedOverlay(ViewFamily))
{
return;
}
TryInit();
RDG_EVENT_SCOPE_STAT(GraphBuilder, CompositionBeforeBasePass, "CompositionBeforeBasePass");
RDG_GPU_STAT_SCOPE(GraphBuilder, CompositionBeforeBasePass);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const FAOConfig& ViewConfig = ViewAOConfigs[ViewIndex];
const bool bEnableSSAO = ViewConfig.SSAOLocation == ESSAOLocation::BeforeBasePass;
const bool bEnableDecals = DecalVisibility && DecalVisibility->HasStage(ViewIndex, EDecalRenderStage::BeforeBasePass);
if (!bEnableDecals && !bEnableSSAO)
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
View.BeginRenderView();
// decals are before AmbientOcclusion so the decal can output a normal that AO is affected by
if (bEnableDecals)
{
FDeferredDecalPassTextures DecalPassTextures = GetDeferredDecalPassTextures(GraphBuilder, View, SubstrateSceneData, SceneTextures, &DBufferTextures, EDecalRenderStage::BeforeBasePass);
TConstArrayView<const FVisibleDecal*> SortedDecals = DecalVisibility->FinishRelevantDecals(ViewIndex, EDecalRenderStage::BeforeBasePass);
AddDeferredDecalPass(GraphBuilder, View, SortedDecals, DecalPassTextures, InstanceCullingManager, EDecalRenderStage::BeforeBasePass);
}
if (bEnableSSAO)
{
FSSAOCommonParameters Parameters = GetSSAOCommonParameters(GraphBuilder, View, SceneTextures.UniformBuffer, ViewConfig.Levels, false);
FScreenPassRenderTarget FinalTarget = FScreenPassRenderTarget(SceneTextures.ScreenSpaceAO, View.ViewRect, ERenderTargetLoadAction::ENoAction);
AddPostProcessingAmbientOcclusion(
GraphBuilder,
View,
Parameters,
FinalTarget);
}
}
}
void FCompositionLighting::ProcessAfterBasePass(FRDGBuilder& GraphBuilder, FInstanceCullingManager& InstanceCullingManager, EProcessAfterBasePassMode Mode, const FSubstrateSceneData& SubstrateSceneData)
{
if (HasRayTracedOverlay(ViewFamily))
{
return;
}
check(bInitialized);
RDG_EVENT_SCOPE_STAT(GraphBuilder, CompositionPreLighting, "LightCompositionTasks_PreLighting");
RDG_GPU_STAT_SCOPE(GraphBuilder, CompositionPreLighting);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const FAOConfig& ViewConfig = ViewAOConfigs[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
View.BeginRenderView();
const auto AddDeferredDecalPassLambda = [&] (const FDeferredDecalPassTextures& DecalPassTextures, EDecalRenderStage Stage)
{
AddDeferredDecalPass(GraphBuilder, View, DecalVisibility->FinishRelevantDecals(ViewIndex, Stage), DecalPassTextures, InstanceCullingManager, Stage);
};
if (DecalVisibility)
{
if (DecalVisibility->HasStage(ViewIndex, EDecalRenderStage::BeforeLighting) && Mode != EProcessAfterBasePassMode::SkipBeforeLightingDecals)
{
// We can disable this pass if using DBuffer decals
// Decals are before AmbientOcclusion so the decal can output a normal that AO is affected by
FDeferredDecalPassTextures DecalPassTextures = GetDeferredDecalPassTextures(GraphBuilder, View, SubstrateSceneData, SceneTextures, nullptr, EDecalRenderStage::BeforeLighting);
AddDeferredDecalPassLambda(DecalPassTextures, EDecalRenderStage::BeforeLighting);
}
if (DecalVisibility->HasStage(ViewIndex, EDecalRenderStage::Emissive) && Mode != EProcessAfterBasePassMode::OnlyBeforeLightingDecals)
{
// DBuffer decals with emissive component
FDeferredDecalPassTextures DecalPassTextures = GetDeferredDecalPassTextures(GraphBuilder, View, SubstrateSceneData, SceneTextures, nullptr, EDecalRenderStage::Emissive);
AddDeferredDecalPassLambda(DecalPassTextures, EDecalRenderStage::Emissive);
}
}
// Forward shading SSAO is applied before the base pass using only the depth buffer.
if (!IsForwardShadingEnabled(View.GetShaderPlatform()) && Mode != EProcessAfterBasePassMode::OnlyBeforeLightingDecals)
{
if (ViewConfig.Levels > 0)
{
const bool bScreenSpaceAOIsProduced = SceneTextures.ScreenSpaceAO->HasBeenProduced();
FScreenPassRenderTarget FinalTarget = FScreenPassRenderTarget(SceneTextures.ScreenSpaceAO, View.ViewRect, bScreenSpaceAOIsProduced ? ERenderTargetLoadAction::ELoad : ERenderTargetLoadAction::ENoAction);
FScreenPassTexture AmbientOcclusion = bScreenSpaceAOIsProduced ? FinalTarget : FScreenPassTexture();
// If doing the Split GTAO method then we need to do the second part here.
if (ViewConfig.GTAOType == EGTAOType::EAsyncHorizonSearch || ViewConfig.GTAOType == EGTAOType::EAsyncCombinedSpatial)
{
check(HorizonsTexture);
FGTAOCommonParameters Parameters = GetGTAOCommonParameters(GraphBuilder, View, SceneTextures.UniformBuffer, ViewConfig.GTAOType);
FScreenPassTexture GTAOHorizons(HorizonsTexture, Parameters.DownsampledViewRect);
AmbientOcclusion = AddPostProcessingGTAOPostAsync(GraphBuilder, View, Parameters, GTAOHorizons, FinalTarget);
ensureMsgf(
!DecalVisibility || !DecalVisibility->HasStage(ViewIndex, EDecalRenderStage::AmbientOcclusion),
TEXT("Ambient occlusion decals are not supported with Async compute SSAO."));
}
else
{
if (ViewConfig.GTAOType == EGTAOType::ENonAsync)
{
FGTAOCommonParameters Parameters = GetGTAOCommonParameters(GraphBuilder, View, SceneTextures.UniformBuffer, ViewConfig.GTAOType);
AmbientOcclusion = AddPostProcessingGTAOAllPasses(GraphBuilder, View, Parameters, FinalTarget);
}
else if (ViewConfig.SSAOLocation == ESSAOLocation::AfterBasePass)
{
FSSAOCommonParameters Parameters = GetSSAOCommonParameters(GraphBuilder, View, SceneTextures.UniformBuffer, ViewConfig.Levels, true);
AmbientOcclusion = AddPostProcessingAmbientOcclusion(GraphBuilder, View, Parameters, FinalTarget);
}
if (DecalVisibility)
{
FDeferredDecalPassTextures DecalPassTextures = GetDeferredDecalPassTextures(GraphBuilder, View, SubstrateSceneData, SceneTextures, nullptr, EDecalRenderStage::AmbientOcclusion);
DecalPassTextures.ScreenSpaceAO = AmbientOcclusion.Texture;
AddDeferredDecalPassLambda(DecalPassTextures, EDecalRenderStage::AmbientOcclusion);
}
}
}
}
}
}
void FCompositionLighting::ProcessAfterOcclusion(FRDGBuilder& GraphBuilder)
{
if (HasRayTracedOverlay(ViewFamily))
{
return;
}
TryInit();
RDG_ASYNC_COMPUTE_BUDGET_SCOPE(GraphBuilder, FSSAOHelper::GetAmbientOcclusionAsyncComputeBudget());
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
const FAOConfig& ViewConfig = ViewAOConfigs[ViewIndex];
if (ViewConfig.GTAOType == EGTAOType::EAsyncCombinedSpatial || ViewConfig.GTAOType == EGTAOType::EAsyncHorizonSearch)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
FGTAOCommonParameters CommonParameters = GetGTAOCommonParameters(GraphBuilder, View, SceneTextures.UniformBuffer, ViewConfig.GTAOType);
const ERenderTargetLoadAction LoadAction = View.DecayLoadAction(ERenderTargetLoadAction::ENoAction);
if (!HorizonsTexture)
{
const FIntPoint HorizonTextureSize = FIntPoint::DivideAndRoundUp(SceneTextures.Config.Extent, CommonParameters.DownscaleFactor);
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(HorizonTextureSize, PF_R8G8, FClearValueBinding::White, TexCreate_UAV | TexCreate_RenderTargetable);
HorizonsTexture = GraphBuilder.CreateTexture(Desc, TEXT("ScreenSpaceGTAOHorizons"));
}
FScreenPassRenderTarget GTAOHorizons(HorizonsTexture, CommonParameters.DownsampledViewRect, LoadAction);
AddPostProcessingGTAOAsyncPasses(
GraphBuilder,
View,
CommonParameters,
GTAOHorizons);
}
}
}