// Copyright Epic Games, Inc. All Rights Reserved. #include "TranslucentRendering.h" #include "DeferredShadingRenderer.h" #include "BasePassRendering.h" #include "DynamicPrimitiveDrawing.h" #include "RendererModule.h" #include "ScenePrivate.h" #include "SceneTextureParameters.h" #include "ScreenRendering.h" #include "ScreenPass.h" #include "MeshPassProcessor.inl" #include "VolumetricRenderTarget.h" #include "VariableRateShadingImageManager.h" #include "Lumen/LumenTranslucencyVolumeLighting.h" #include "VirtualShadowMaps/VirtualShadowMapArray.h" #include "Strata/Strata.h" #include "HairStrands/HairStrandsUtils.h" #include "PixelShaderUtils.h" #include "OIT/OIT.h" #include "OIT/OITParameters.h" #include "DynamicResolutionState.h" #include "TemporalAA.h" DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQueryFence Wait"), STAT_TranslucencyTimestampQueryFence_Wait, STATGROUP_SceneRendering); DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQuery Wait"), STAT_TranslucencyTimestampQuery_Wait, STATGROUP_SceneRendering); DECLARE_CYCLE_STAT(TEXT("Translucency"), STAT_CLP_Translucency, STATGROUP_ParallelCommandListMarkers); DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucency GPU Time (MS)"), STAT_TranslucencyGPU, STATGROUP_SceneRendering); DEFINE_GPU_DRAWCALL_STAT(Translucency); static TAutoConsoleVariable CVarSeparateTranslucencyScreenPercentage( TEXT("r.SeparateTranslucencyScreenPercentage"), 100.0f, TEXT("Render separate translucency at this percentage of the full resolution.\n") TEXT("in percent, >0 and <=100, larger numbers are possible (supersampling).") TEXT("<0 is treated like 100."), ECVF_Scalability | ECVF_Default); static TAutoConsoleVariable CVarTranslucencyScreenPercentageBasis( TEXT("r.Translucency.ScreenPercentage.Basis"), 0, TEXT("Basis of the translucency's screen percentage (Experimental).\n") TEXT(" 0: Uses the primary view's resolution (notably scaling with r.ScreenPercentage and r.DynamicRes.*)\n") TEXT(" 1: Uses the secondary view's resolution (temporal upscale's output resolution)"), ECVF_Scalability | ECVF_Default); static TAutoConsoleVariable CVarTranslucencyMinScreenPercentage( TEXT("r.Translucency.DynamicRes.MinScreenPercentage"), DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultMinResolutionFraction), TEXT("Minimal screen percentage for translucency."), ECVF_RenderThreadSafe | ECVF_Default); static TAutoConsoleVariable CVarTranslucencyTimeBudget( TEXT("r.Translucency.DynamicRes.TimeBudget"), DynamicRenderScaling::FHeuristicSettings::kBudgetMsDisabled, TEXT("Frame's time budget for translucency rendering in milliseconds."), ECVF_RenderThreadSafe | ECVF_Default); static TAutoConsoleVariable CVarTranslucencyTargetedHeadRoomPercentage( TEXT("r.Translucency.DynamicRes.TargetedHeadRoomPercentage"), DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultTargetedHeadRoom), TEXT("Targeted GPU headroom for translucency (in percent from r.DynamicRes.DynamicRes.TimeBudget)."), ECVF_RenderThreadSafe | ECVF_Default); static TAutoConsoleVariable CVarTranslucencyChangeThreshold( TEXT("r.Translucency.DynamicRes.ChangePercentageThreshold"), DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultChangeThreshold), TEXT("Minimal increase percentage threshold to alow when changing resolution of translucency."), ECVF_RenderThreadSafe | ECVF_Default); int32 GSeparateTranslucencyUpsampleMode = 1; static FAutoConsoleVariableRef CVarSeparateTranslucencyUpsampleMode( TEXT("r.SeparateTranslucencyUpsampleMode"), GSeparateTranslucencyUpsampleMode, TEXT("Upsample method to use on separate translucency. These are only used when r.SeparateTranslucencyScreenPercentage is less than 100.\n") TEXT("0: bilinear 1: Nearest-Depth Neighbor (only when r.SeparateTranslucencyScreenPercentage is 50)"), ECVF_Scalability | ECVF_Default); static TAutoConsoleVariable CVarRHICmdFlushRenderThreadTasksTranslucentPass( TEXT("r.RHICmdFlushRenderThreadTasksTranslucentPass"), 0, TEXT("Wait for completion of parallel render thread tasks at the end of the translucent pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksTranslucentPass is > 0 we will flush.")); static TAutoConsoleVariable CVarParallelTranslucency( TEXT("r.ParallelTranslucency"), 1, TEXT("Toggles parallel translucency rendering. Parallel rendering must be enabled for this to have an effect."), ECVF_RenderThreadSafe); DynamicRenderScaling::FHeuristicSettings GetDynamicTranslucencyResolutionSettings() { DynamicRenderScaling::FHeuristicSettings BucketSetting; BucketSetting.Model = DynamicRenderScaling::EHeuristicModel::Quadratic; BucketSetting.bModelScalesWithPrimaryScreenPercentage = CVarTranslucencyScreenPercentageBasis.GetValueOnAnyThread() != 1; BucketSetting.MinResolutionFraction = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyMinScreenPercentage); BucketSetting.BudgetMs = CVarTranslucencyTimeBudget.GetValueOnAnyThread(); BucketSetting.ChangeThreshold = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyChangeThreshold); BucketSetting.TargetedHeadRoom = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyTargetedHeadRoomPercentage); return BucketSetting; } DynamicRenderScaling::FBudget GDynamicTranslucencyResolution(TEXT("DynamicTranslucencyResolution"), &GetDynamicTranslucencyResolutionSettings); static const TCHAR* kTranslucencyPassName[] = { TEXT("BeforeDistortion"), TEXT("AfterDOF"), TEXT("AfterDOFModulate"), TEXT("AfterMotionBlur"), TEXT("All"), }; static_assert(UE_ARRAY_COUNT(kTranslucencyPassName) == int32(ETranslucencyPass::TPT_MAX), "Fix me"); static const TCHAR* kTranslucencyColorTextureName[] = { TEXT("Translucency.BeforeDistortion.Color"), TEXT("Translucency.AfterDOF.Color"), TEXT("Translucency.AfterDOF.Modulate"), TEXT("Translucency.AfterMotionBlur.Color"), TEXT("Translucency.All.Color"), }; static_assert(UE_ARRAY_COUNT(kTranslucencyColorTextureName) == int32(ETranslucencyPass::TPT_MAX), "Fix me"); static const TCHAR* TranslucencyPassToString(ETranslucencyPass::Type TranslucencyPass) { return kTranslucencyPassName[TranslucencyPass]; } EMeshPass::Type TranslucencyPassToMeshPass(ETranslucencyPass::Type TranslucencyPass) { EMeshPass::Type TranslucencyMeshPass = EMeshPass::Num; switch (TranslucencyPass) { case ETranslucencyPass::TPT_StandardTranslucency: TranslucencyMeshPass = EMeshPass::TranslucencyStandard; break; case ETranslucencyPass::TPT_TranslucencyAfterDOF: TranslucencyMeshPass = EMeshPass::TranslucencyAfterDOF; break; case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate: TranslucencyMeshPass = EMeshPass::TranslucencyAfterDOFModulate; break; case ETranslucencyPass::TPT_TranslucencyAfterMotionBlur: TranslucencyMeshPass = EMeshPass::TranslucencyAfterMotionBlur; break; case ETranslucencyPass::TPT_AllTranslucency: TranslucencyMeshPass = EMeshPass::TranslucencyAll; break; } check(TranslucencyMeshPass != EMeshPass::Num); return TranslucencyMeshPass; } ETranslucencyView GetTranslucencyView(const FViewInfo& View) { #if RHI_RAYTRACING if (ShouldRenderRayTracingTranslucency(View)) { return ETranslucencyView::RayTracing; } #endif return View.IsUnderwater() ? ETranslucencyView::UnderWater : ETranslucencyView::AboveWater; } ETranslucencyView GetTranslucencyViews(TArrayView Views) { ETranslucencyView TranslucencyViews = ETranslucencyView::None; for (const FViewInfo& View : Views) { TranslucencyViews |= GetTranslucencyView(View); } return TranslucencyViews; } /** Mostly used to know if debug rendering should be drawn in this pass */ static bool IsMainTranslucencyPass(ETranslucencyPass::Type TranslucencyPass) { return TranslucencyPass == ETranslucencyPass::TPT_AllTranslucency || TranslucencyPass == ETranslucencyPass::TPT_StandardTranslucency; } static bool IsParallelTranslucencyEnabled() { return GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread(); } static bool IsTranslucencyWaitForTasksEnabled() { return IsParallelTranslucencyEnabled() && (CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0); } static bool IsSeparateTranslucencyEnabled(ETranslucencyPass::Type TranslucencyPass, float DownsampleScale) { // Currently AfterDOF is rendered earlier in the frame and must be rendered in a separate texture. if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF || TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate || TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur ) { return true; } // Otherwise it only gets rendered in the separate buffer if it is downsampled. if (DownsampleScale < 1.0f) { return true; } return false; } static int GetSSRQuality() { static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.SSR.Quality")); int SSRQuality = CVar ? (CVar->GetInt()) : 0; return SSRQuality; } static bool ShouldRenderTranslucencyScreenSpaceReflections(const FViewInfo& View) { // The screenspace reflection of translucency is not controlled by the postprocessing setting // or the raytracing overlay setting. It needs to be turned on/off dynamically to support // diffuse only if (!View.Family->EngineShowFlags.ScreenSpaceReflections) { return false; } int SSRQuality = GetSSRQuality(); if (SSRQuality <= 0) { return false; } return true; } FSeparateTranslucencyDimensions UpdateSeparateTranslucencyDimensions(const FViewFamilyInfo& ActiveViewFamily) { float TranslucencyResolutionFraction = FMath::Clamp(CVarSeparateTranslucencyScreenPercentage.GetValueOnRenderThread() / 100.0f, 0.0f, 1.0f); float MaxTranslucencyResolutionFraction = TranslucencyResolutionFraction; if (GDynamicTranslucencyResolution.GetSettings().IsEnabled()) { TranslucencyResolutionFraction = ActiveViewFamily.DynamicResolutionFractions[GDynamicTranslucencyResolution]; MaxTranslucencyResolutionFraction = ActiveViewFamily.DynamicResolutionUpperBounds[GDynamicTranslucencyResolution]; } if (CVarTranslucencyScreenPercentageBasis.GetValueOnRenderThread() == 1) { TranslucencyResolutionFraction /= ActiveViewFamily.DynamicResolutionFractions[GDynamicPrimaryResolutionFraction]; MaxTranslucencyResolutionFraction /= ActiveViewFamily.DynamicResolutionUpperBounds[GDynamicPrimaryResolutionFraction]; } FSeparateTranslucencyDimensions Dimensions; // TODO: this should be MaxTranslucencyResolutionFraction instead of TranslucencyResolutionFraction to keep the size of render target stable, but the SvPositionToBuffer() is broken in material. Dimensions.Extent = GetScaledExtent(ActiveViewFamily.SceneTexturesConfig.Extent, TranslucencyResolutionFraction); Dimensions.NumSamples = ActiveViewFamily.SceneTexturesConfig.NumSamples; Dimensions.Scale = TranslucencyResolutionFraction; return Dimensions; } FTranslucencyPassResourcesMap::FTranslucencyPassResourcesMap(int32 NumViews) { Array.SetNum(NumViews); for (int32 ViewIndex = 0; ViewIndex < NumViews; ViewIndex++) { for (int32 i = 0; i < int32(ETranslucencyPass::TPT_MAX); i++) { Array[ViewIndex][i].Pass = ETranslucencyPass::Type(i); } } } /** Pixel shader used to copy scene color into another texture so that materials can read from scene color with a node. */ class FCopySceneColorPS : public FGlobalShader { public: DECLARE_GLOBAL_SHADER(FCopySceneColorPS); SHADER_USE_PARAMETER_STRUCT(FCopySceneColorPS, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } }; IMPLEMENT_GLOBAL_SHADER(FCopySceneColorPS, "/Engine/Private/TranslucentLightingShaders.usf", "CopySceneColorMain", SF_Pixel); static FRDGTextureRef AddCopySceneColorPass(FRDGBuilder& GraphBuilder, TArrayView Views, FRDGTextureMSAA SceneColor) { FRDGTextureRef SceneColorCopyTexture = nullptr; ERenderTargetLoadAction LoadAction = ERenderTargetLoadAction::ENoAction; RDG_EVENT_SCOPE(GraphBuilder, "CopySceneColor"); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { const FViewInfo& View = Views[ViewIndex]; if (View.IsUnderwater()) { continue; } bool bNeedsResolve = false; for (int32 TranslucencyPass = 0; TranslucencyPass < ETranslucencyPass::TPT_MAX; ++TranslucencyPass) { if (View.TranslucentPrimCount.UseSceneColorCopy((ETranslucencyPass::Type)TranslucencyPass)) { bNeedsResolve = true; break; } } if (bNeedsResolve) { RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); AddResolveSceneColorPass(GraphBuilder, View, SceneColor); const FIntPoint SceneColorExtent = SceneColor.Target->Desc.Extent; if (!SceneColorCopyTexture) { SceneColorCopyTexture = GraphBuilder.CreateTexture(FRDGTextureDesc::Create2D(SceneColorExtent, PF_B8G8R8A8, FClearValueBinding::White, TexCreate_ShaderResource | TexCreate_RenderTargetable), TEXT("SceneColorCopy")); } const FScreenPassTextureViewport Viewport(SceneColorCopyTexture, View.ViewRect); TShaderMapRef VertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->View = View.ViewUniformBuffer; PassParameters->SceneColorTexture = SceneColor.Resolve; PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorCopyTexture, LoadAction); if (!View.Family->bMultiGPUForkAndJoin) { LoadAction = ERenderTargetLoadAction::ELoad; } AddDrawScreenPass(GraphBuilder, {}, View, Viewport, Viewport, VertexShader, PixelShader, PassParameters); } } return SceneColorCopyTexture; } class FComposeSeparateTranslucencyPS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FComposeSeparateTranslucencyPS); SHADER_USE_PARAMETER_STRUCT(FComposeSeparateTranslucencyPS, FGlobalShader); class FNearestDepthNeighborUpsampling : SHADER_PERMUTATION_BOOL("PERMUTATION_NEARESTDEPTHNEIGHBOR"); using FPermutationDomain = TShaderPermutationDomain; BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER(FScreenTransform, ScreenPosToSceneColorUV) SHADER_PARAMETER(FScreenTransform, ScreenPosToSeparateTranslucencyUV) SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMin) SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMax) SHADER_PARAMETER(FVector2f, SeparateTranslucencyExtentInverse) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SceneColorSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateTranslucencyPointTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SeparateTranslucencyPointSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateModulationPointTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SeparateModulationPointSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateTranslucencyBilinearTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SeparateTranslucencyBilinearSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateModulationBilinearTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SeparateModulationBilinearSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, LowResDepthTexture) SHADER_PARAMETER_SAMPLER(SamplerState, LowResDepthSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, FullResDepthTexture) SHADER_PARAMETER_SAMPLER(SamplerState, FullResDepthSampler) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } }; class FTranslucencyUpsampleResponsiveAAPS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FTranslucencyUpsampleResponsiveAAPS); SHADER_USE_PARAMETER_STRUCT(FTranslucencyUpsampleResponsiveAAPS, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER(FIntPoint, StencilPixelPosMin) SHADER_PARAMETER(FIntPoint, StencilPixelPosMax) SHADER_PARAMETER(FScreenTransform, SvPositionToStencilPixelCoord) SHADER_PARAMETER(int32, StencilMask) SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, StencilTexture) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } }; IMPLEMENT_GLOBAL_SHADER(FComposeSeparateTranslucencyPS, "/Engine/Private/ComposeSeparateTranslucency.usf", "MainPS", SF_Pixel); IMPLEMENT_GLOBAL_SHADER(FTranslucencyUpsampleResponsiveAAPS, "/Engine/Private/TranslucencyUpsampling.usf", "UpsampleResponsiveAAPS", SF_Pixel); FScreenPassTexture FTranslucencyComposition::AddPass( FRDGBuilder& GraphBuilder, const FViewInfo& View, const FTranslucencyPassResources& TranslucencyTextures) const { // if nothing is rendered into the separate translucency, then just return the existing Scenecolor ensure(TranslucencyTextures.IsValid()); if (!TranslucencyTextures.IsValid()) { return SceneColor; } FRDGTextureRef SeparateModulationTexture = TranslucencyTextures.GetColorModulateForRead(GraphBuilder); FRDGTextureRef SeparateTranslucencyTexture = TranslucencyTextures.GetColorForRead(GraphBuilder); FScreenPassTextureViewport SceneColorViewport(FIntPoint(1, 1), FIntRect(0, 0, 1, 1)); if (SceneColor.IsValid()) { SceneColorViewport = FScreenPassTextureViewport(SceneColor); } FScreenPassTextureViewport TranslucencyViewport(FIntPoint(1, 1), FIntRect(0, 0, 1, 1)); if (TranslucencyTextures.ColorTexture.IsValid()) { TranslucencyViewport = FScreenPassTextureViewport(TranslucencyTextures.ColorTexture.Resolve, TranslucencyTextures.ViewRect); } else if (TranslucencyTextures.ColorModulateTexture.IsValid()) { TranslucencyViewport = FScreenPassTextureViewport(TranslucencyTextures.ColorModulateTexture.Resolve, TranslucencyTextures.ViewRect); } bool bPostMotionBlur = TranslucencyTextures.Pass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur; if (bPostMotionBlur) { check(!bApplyModulateOnly); } else if (bApplyModulateOnly) { if (!TranslucencyTextures.ColorModulateTexture.IsValid()) { return SceneColor; } SeparateTranslucencyTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy); } RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency); DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution); const TCHAR* OpName = nullptr; FRHIBlendState* BlendState = nullptr; FRDGTextureRef NewSceneColor = nullptr; if (Operation == EOperation::UpscaleOnly) { check(!SceneColor.IsValid()); ensure(!TranslucencyTextures.ColorModulateTexture.IsValid()); OpName = TEXT("UpscaleTranslucency"); FRDGTextureDesc OutputDesc = FRDGTextureDesc::Create2D( OutputViewport.Extent, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource); NewSceneColor = GraphBuilder.CreateTexture( OutputDesc, bPostMotionBlur ? TEXT("PostMotionBlurTranslucency.SceneColor") : TEXT("PostDOFTranslucency.SceneColor")); } else if (Operation == EOperation::ComposeToExistingSceneColor) { check(SceneColor.IsValid()); ensure(!TranslucencyTextures.ColorModulateTexture.IsValid()); OpName = TEXT("ComposeTranslucencyToExistingColor"); BlendState = TStaticBlendState::GetRHI(); ensure(SceneColor.Texture->Desc.Flags & TexCreate_RenderTargetable); NewSceneColor = SceneColor.Texture; } else if (Operation == EOperation::ComposeToNewSceneColor) { check(SceneColor.IsValid()); OpName = TEXT("ComposeTranslucencyToNewSceneColor"); FRDGTextureDesc OutputDesc = FRDGTextureDesc::Create2D( OutputViewport.Extent, OutputPixelFormat != PF_Unknown ? OutputPixelFormat : SceneColor.Texture->Desc.Format, FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource); NewSceneColor = GraphBuilder.CreateTexture( OutputDesc, bPostMotionBlur ? TEXT("PostMotionBlurTranslucency.SceneColor") : TEXT("PostDOFTranslucency.SceneColor")); } else { unimplemented(); } const FVector2f SeparateTranslucencyExtentInv = FVector2f(1.0f, 1.0f) / FVector2f(TranslucencyViewport.Extent); const bool bScaleSeparateTranslucency = OutputViewport.Rect.Size() != TranslucencyTextures.ViewRect.Size(); const float DownsampleScale = float(TranslucencyTextures.ViewRect.Width()) / float(OutputViewport.Rect.Width()); const bool DepthUpscampling = ( bScaleSeparateTranslucency && TranslucencyTextures.DepthTexture.IsValid() && SceneDepth.IsValid() && FMath::IsNearlyEqual(DownsampleScale, 0.5f) && GSeparateTranslucencyUpsampleMode > 0); FScreenTransform SvPositionToViewportUV = FScreenTransform::SvPositionToViewportUV(OutputViewport.Rect); FComposeSeparateTranslucencyPS::FParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->ScreenPosToSceneColorUV = SvPositionToViewportUV * FScreenTransform::ChangeTextureBasisFromTo( SceneColorViewport, FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV); PassParameters->ScreenPosToSeparateTranslucencyUV = SvPositionToViewportUV * FScreenTransform::ChangeTextureBasisFromTo( TranslucencyViewport, FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV); PassParameters->SeparateTranslucencyUVMin = (FVector2f(TranslucencyViewport.Rect.Min) + FVector2f(0.5f, 0.5f)) * SeparateTranslucencyExtentInv; PassParameters->SeparateTranslucencyUVMax = (FVector2f(TranslucencyViewport.Rect.Max) - FVector2f(0.5f, 0.5f)) * SeparateTranslucencyExtentInv; PassParameters->SeparateTranslucencyExtentInverse = SeparateTranslucencyExtentInv; PassParameters->SceneColorTexture = Operation == EOperation::ComposeToNewSceneColor ? SceneColor.Texture : GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy); PassParameters->SceneColorSampler = TStaticSamplerState::GetRHI(); PassParameters->SeparateTranslucencyPointTexture = SeparateTranslucencyTexture; PassParameters->SeparateTranslucencyPointSampler = TStaticSamplerState::GetRHI(); PassParameters->SeparateModulationPointTexture = SeparateModulationTexture; PassParameters->SeparateModulationPointSampler = TStaticSamplerState::GetRHI(); PassParameters->SeparateTranslucencyBilinearTexture = SeparateTranslucencyTexture; PassParameters->SeparateTranslucencyBilinearSampler = TStaticSamplerState::GetRHI(); PassParameters->SeparateModulationBilinearTexture = SeparateModulationTexture; PassParameters->SeparateModulationBilinearSampler = TStaticSamplerState::GetRHI(); PassParameters->ViewUniformBuffer = View.ViewUniformBuffer; if (Operation == EOperation::ComposeToExistingSceneColor) { PassParameters->RenderTargets[0] = FRenderTargetBinding(NewSceneColor, ERenderTargetLoadAction::ELoad); } else { PassParameters->RenderTargets[0] = FRenderTargetBinding(NewSceneColor, ERenderTargetLoadAction::ENoAction); } if (DepthUpscampling) { PassParameters->LowResDepthTexture = TranslucencyTextures.GetDepthForRead(GraphBuilder); PassParameters->LowResDepthSampler = TStaticSamplerState::GetRHI(); PassParameters->FullResDepthTexture = SceneDepth.Texture; PassParameters->FullResDepthSampler = TStaticSamplerState::GetRHI(); } FComposeSeparateTranslucencyPS::FPermutationDomain PermutationVector; PermutationVector.Set(DepthUpscampling); TShaderMapRef PixelShader(View.ShaderMap, PermutationVector); FPixelShaderUtils::AddFullscreenPass( GraphBuilder, View.ShaderMap, RDG_EVENT_NAME( "%s(%s%s%s) %dx%d -> %dx%d", OpName, kTranslucencyPassName[int32(TranslucencyTextures.Pass)], bApplyModulateOnly ? TEXT(" ModulateOnly") : TEXT(""), DepthUpscampling ? TEXT(" DepthUpscampling") : TEXT(""), TranslucencyTextures.ViewRect.Width(), TranslucencyTextures.ViewRect.Height(), OutputViewport.Rect.Width(), OutputViewport.Rect.Height()), PixelShader, PassParameters, OutputViewport.Rect, BlendState); return FScreenPassTexture(NewSceneColor, OutputViewport.Rect); } static void AddUpsampleResponsiveAAPass( FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture DownsampledTranslucencyDepth, FRDGTextureRef OutputDepthTexture) { FTranslucencyUpsampleResponsiveAAPS::FParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->StencilPixelPosMin = DownsampledTranslucencyDepth.ViewRect.Min; PassParameters->StencilPixelPosMax = DownsampledTranslucencyDepth.ViewRect.Max - 1; PassParameters->SvPositionToStencilPixelCoord = (FScreenTransform::Identity - View.ViewRect.Min) * (FVector2f(DownsampledTranslucencyDepth.ViewRect.Size()) / FVector2f(View.ViewRect.Size())) + DownsampledTranslucencyDepth.ViewRect.Min; PassParameters->StencilMask = STENCIL_TEMPORAL_RESPONSIVE_AA_MASK; PassParameters->StencilTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(DownsampledTranslucencyDepth.Texture, PF_X24_G8)); PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(OutputDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthNop_StencilWrite); TShaderMapRef VertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState::GetRHI(); FRHIBlendState* BlendState = TStaticBlendState::GetRHI(); const FScreenPassPipelineState PipelineState(VertexShader, PixelShader, BlendState, DepthStencilState, /* StencilRef = */ STENCIL_TEMPORAL_RESPONSIVE_AA_MASK); ClearUnusedGraphResources(PixelShader, PassParameters); GraphBuilder.AddPass( RDG_EVENT_NAME("UpsampleResponsiveAA %dx%d -> %dx%d", DownsampledTranslucencyDepth.ViewRect.Width(), DownsampledTranslucencyDepth.ViewRect.Height(), View.ViewRect.Width(), View.ViewRect.Height()), PassParameters, ERDGPassFlags::Raster, [&View, PipelineState, PixelShader, PassParameters](FRHICommandList& RHICmdList) { FScreenPassTextureViewport OutputViewport(PassParameters->RenderTargets.DepthStencil.GetTexture()->Desc.Extent, View.ViewRect); DrawScreenPass(RHICmdList, View, OutputViewport, OutputViewport, PipelineState, EScreenPassDrawFlags::None, [&](FRHICommandList&) { SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters); }); }); } bool FSceneRenderer::ShouldRenderTranslucency() const { return ActiveViewFamily->EngineShowFlags.Translucency && !ActiveViewFamily->EngineShowFlags.VisualizeLightCulling && !ActiveViewFamily->UseDebugViewPS(); } bool FSceneRenderer::ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass) const { extern int32 GLightShaftRenderAfterDOF; // Change this condition to control where simple elements should be rendered. if (IsMainTranslucencyPass(TranslucencyPass)) { for (const FViewInfo& View : Views) { if (View.bHasTranslucentViewMeshElements || View.SimpleElementCollector.BatchedElements.HasPrimsToDraw()) { return true; } } } // If lightshafts are rendered in low res, we must reset the offscreen buffer in case is was also used in TPT_StandardTranslucency. if (GLightShaftRenderAfterDOF && TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF) { return true; } for (const FViewInfo& View : Views) { if (View.TranslucentPrimCount.Num(TranslucencyPass) > 0) { return true; } } return false; } FScreenPassTextureViewport FSeparateTranslucencyDimensions::GetInstancedStereoViewport(const FViewInfo& View) const { FIntRect ViewRect = View.ViewRect; if (View.IsInstancedStereoPass() && !View.bIsMultiViewEnabled) { ViewRect.Max.X = ViewRect.Min.X + View.InstancedStereoWidth; } ViewRect = GetScaledRect(ViewRect, Scale); return FScreenPassTextureViewport(Extent, ViewRect); } void SetupPostMotionBlurTranslucencyViewParameters(const FViewInfo& View, FViewUniformShaderParameters& Parameters) { // post-motionblur pass without down-sampling requires no Temporal AA jitter FBox VolumeBounds[TVC_MAX]; FViewMatrices ModifiedViewMatrices = View.ViewMatrices; ModifiedViewMatrices.HackRemoveTemporalAAProjectionJitter(); Parameters = *View.CachedViewUniformShaderParameters; View.SetupUniformBufferParameters(ModifiedViewMatrices, ModifiedViewMatrices, VolumeBounds, TVC_MAX, Parameters); } FRDGTextureMSAA CreatePostDOFTranslucentTexture( FRDGBuilder& GraphBuilder, ETranslucencyPass::Type TranslucencyPass, FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions, bool bIsModulate, EShaderPlatform ShaderPlatform) { const bool bNeedUAV = SeparateTranslucencyDimensions.NumSamples == 1 && OIT::IsEnabled(EOITSortingType::SortedPixels, ShaderPlatform); const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D( SeparateTranslucencyDimensions.Extent, bIsModulate ? PF_FloatR11G11B10 : PF_FloatRGBA, bIsModulate ? FClearValueBinding::White : FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource | (bNeedUAV ? TexCreate_UAV : TexCreate_None), 1, SeparateTranslucencyDimensions.NumSamples); return CreateTextureMSAA( GraphBuilder, Desc, kTranslucencyColorTextureName[int32(TranslucencyPass)], bIsModulate ? GFastVRamConfig.SeparateTranslucencyModulate : GFastVRamConfig.SeparateTranslucency); } void SetupDownsampledTranslucencyViewParameters( const FViewInfo& View, FIntPoint TextureExtent, FIntRect ViewRect, ETranslucencyPass::Type TranslucencyPass, FViewUniformShaderParameters& DownsampledTranslucencyViewParameters) { DownsampledTranslucencyViewParameters = *View.CachedViewUniformShaderParameters; FViewMatrices ViewMatrices = View.ViewMatrices; FViewMatrices PrevViewMatrices = View.PrevViewInfo.ViewMatrices; if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur) { // Remove jitter from this pass ViewMatrices.HackRemoveTemporalAAProjectionJitter(); PrevViewMatrices.HackRemoveTemporalAAProjectionJitter(); } // Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect View.SetupViewRectUniformBufferParameters( DownsampledTranslucencyViewParameters, TextureExtent, ViewRect, ViewMatrices, PrevViewMatrices); // instead of using the expected ratio, use the actual dimensions to avoid rounding errors float ActualDownsampleX = float(ViewRect.Width()) / float(View.ViewRect.Width()); float ActualDownsampleY = float(ViewRect.Height()) / float(View.ViewRect.Height()); DownsampledTranslucencyViewParameters.LightProbeSizeRatioAndInvSizeRatio = FVector4f(ActualDownsampleX, ActualDownsampleY, 1.0f / ActualDownsampleX, 1.0f / ActualDownsampleY); DownsampledTranslucencyViewParameters.BufferToSceneTextureScale = FVector2f(1.0f / ActualDownsampleX, 1.0f / ActualDownsampleY); } TRDGUniformBufferRef CreateTranslucentBasePassUniformBuffer( FRDGBuilder& GraphBuilder, const FScene* Scene, const FViewInfo& View, const int32 ViewIndex, const FTranslucencyLightingVolumeTextures& TranslucencyLightingVolumeTextures, FRDGTextureRef SceneColorCopyTexture, const ESceneTextureSetupMode SceneTextureSetupMode, bool bLumenGIEnabled, const FOITData& OITData) { FTranslucentBasePassUniformParameters& BasePassParameters = *GraphBuilder.AllocParameters(); const auto GetRDG = [&](const TRefCountPtr& PooledRenderTarget, ERDGTextureFlags Flags = ERDGTextureFlags::None) { return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, Flags); }; SetupSharedBasePassParameters(GraphBuilder, View, bLumenGIEnabled, BasePassParameters.Shared); SetupSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), View.FeatureLevel, SceneTextureSetupMode, BasePassParameters.SceneTextures); Strata::BindStrataForwardPasslUniformParameters(GraphBuilder, View, BasePassParameters.Strata); const FLightSceneProxy* SelectedForwardDirectionalLightProxy = View.ForwardLightingResources.SelectedForwardDirectionalLightProxy; SetupLightCloudTransmittanceParameters(GraphBuilder, Scene, View, SelectedForwardDirectionalLightProxy ? SelectedForwardDirectionalLightProxy->GetLightSceneInfo() : nullptr, BasePassParameters.ForwardDirLightCloudShadow); const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder); // Material SSR { float PrevSceneColorPreExposureInvValue = 1.0f / View.PreExposure; if (View.HZB) { BasePassParameters.HZBTexture = View.HZB; BasePassParameters.HZBSampler = TStaticSamplerState::GetRHI(); FRDGTextureRef PrevSceneColorTexture = SystemTextures.Black; FIntRect PrevSceneColorViewRect = FIntRect(0, 0, 1, 1); if (View.PrevViewInfo.CustomSSRInput.IsValid()) { PrevSceneColorTexture = GetRDG(View.PrevViewInfo.CustomSSRInput.RT[0]); PrevSceneColorViewRect = View.PrevViewInfo.CustomSSRInput.ViewportRect; PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure; } else if (View.PrevViewInfo.TemporalAAHistory.IsValid()) { PrevSceneColorTexture = GetRDG(View.PrevViewInfo.TemporalAAHistory.RT[0]); PrevSceneColorViewRect = View.PrevViewInfo.TemporalAAHistory.ViewportRect; PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure; } else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid()) { PrevSceneColorTexture = GetRDG(View.PrevViewInfo.ScreenSpaceRayTracingInput); PrevSceneColorViewRect = View.PrevViewInfo.ViewRect; PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure; } BasePassParameters.PrevSceneColor = PrevSceneColorTexture; BasePassParameters.PrevSceneColorSampler = TStaticSamplerState::GetRHI(); FScreenPassTextureViewportParameters PrevSceneColorParameters = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(PrevSceneColorTexture, PrevSceneColorViewRect)); BasePassParameters.PrevSceneColorBilinearUVMin = PrevSceneColorParameters.UVViewportBilinearMin; BasePassParameters.PrevSceneColorBilinearUVMax = PrevSceneColorParameters.UVViewportBilinearMax; const FVector2f HZBUvFactor( float(View.ViewRect.Width()) / float(2 * View.HZBMipmap0Size.X), float(View.ViewRect.Height()) / float(2 * View.HZBMipmap0Size.Y) ); const FVector4f HZBUvFactorAndInvFactorValue( HZBUvFactor.X, HZBUvFactor.Y, 1.0f / HZBUvFactor.X, 1.0f / HZBUvFactor.Y ); BasePassParameters.HZBUvFactorAndInvFactor = HZBUvFactorAndInvFactorValue; } else { BasePassParameters.HZBTexture = SystemTextures.Black; BasePassParameters.HZBSampler = TStaticSamplerState::GetRHI(); BasePassParameters.PrevSceneColor = SystemTextures.Black; BasePassParameters.PrevSceneColorSampler = TStaticSamplerState::GetRHI(); BasePassParameters.PrevSceneColorBilinearUVMin = FVector2f(0.0f, 0.0f); BasePassParameters.PrevSceneColorBilinearUVMax = FVector2f(1.0f, 1.0f); } BasePassParameters.ApplyVolumetricCloudOnTransparent = 0.0f; BasePassParameters.VolumetricCloudColor = nullptr; BasePassParameters.VolumetricCloudDepth = nullptr; BasePassParameters.VolumetricCloudColorSampler = TStaticSamplerState::GetRHI(); BasePassParameters.VolumetricCloudDepthSampler = TStaticSamplerState::GetRHI(); if (IsVolumetricRenderTargetEnabled() && View.ViewState) { TRefCountPtr VolumetricReconstructRT = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRT(); if (VolumetricReconstructRT.IsValid()) { TRefCountPtr VolumetricReconstructRTDepth = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRTDepth(); BasePassParameters.VolumetricCloudColor = VolumetricReconstructRT->GetRHI(); BasePassParameters.VolumetricCloudDepth = VolumetricReconstructRTDepth->GetRHI(); BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f; } } if (BasePassParameters.VolumetricCloudColor == nullptr) { BasePassParameters.VolumetricCloudColor = GSystemTextures.BlackAlphaOneDummy->GetRHI(); BasePassParameters.VolumetricCloudDepth = GSystemTextures.BlackDummy->GetRHI(); } FIntPoint ViewportOffset = View.ViewRect.Min; FIntPoint ViewportExtent = View.ViewRect.Size(); // Scene render targets might not exist yet; avoids NaNs. FIntPoint EffectiveBufferSize = View.GetSceneTexturesConfig().Extent; EffectiveBufferSize.X = FMath::Max(EffectiveBufferSize.X, 1); EffectiveBufferSize.Y = FMath::Max(EffectiveBufferSize.Y, 1); if (View.PrevViewInfo.CustomSSRInput.IsValid()) { ViewportOffset = View.PrevViewInfo.CustomSSRInput.ViewportRect.Min; ViewportExtent = View.PrevViewInfo.CustomSSRInput.ViewportRect.Size(); EffectiveBufferSize = View.PrevViewInfo.CustomSSRInput.RT[0]->GetDesc().Extent; } else if (View.PrevViewInfo.TemporalAAHistory.IsValid()) { ViewportOffset = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Min; ViewportExtent = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Size(); EffectiveBufferSize = View.PrevViewInfo.TemporalAAHistory.RT[0]->GetDesc().Extent; } else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid()) { ViewportOffset = View.PrevViewInfo.ViewRect.Min; ViewportExtent = View.PrevViewInfo.ViewRect.Size(); EffectiveBufferSize = View.PrevViewInfo.ScreenSpaceRayTracingInput->GetDesc().Extent; } FVector2f InvBufferSize(1.0f / float(EffectiveBufferSize.X), 1.0f / float(EffectiveBufferSize.Y)); FVector4f ScreenPosToPixelValue( ViewportExtent.X * 0.5f * InvBufferSize.X, -ViewportExtent.Y * 0.5f * InvBufferSize.Y, (ViewportExtent.X * 0.5f + ViewportOffset.X) * InvBufferSize.X, (ViewportExtent.Y * 0.5f + ViewportOffset.Y) * InvBufferSize.Y); BasePassParameters.PrevScreenPositionScaleBias = ScreenPosToPixelValue; BasePassParameters.PrevSceneColorPreExposureInv = PrevSceneColorPreExposureInvValue; BasePassParameters.SSRQuality = ShouldRenderTranslucencyScreenSpaceReflections(View) ? GetSSRQuality() : 0; } // Translucency Lighting Volume BasePassParameters.TranslucencyLightingVolume = GetTranslucencyLightingVolumeParameters(GraphBuilder, TranslucencyLightingVolumeTextures, View); BasePassParameters.LumenParameters = GetLumenTranslucencyLightingParameters(GraphBuilder, View.LumenTranslucencyGIVolume, View.LumenFrontLayerTranslucency); const bool bLumenGIHandlingSkylight = bLumenGIEnabled && BasePassParameters.LumenParameters.TranslucencyGIGridSize.Z > 0; BasePassParameters.Shared.UseBasePassSkylight = bLumenGIHandlingSkylight ? 0 : 1; BasePassParameters.SceneColorCopyTexture = SystemTextures.Black; BasePassParameters.SceneColorCopySampler = TStaticSamplerState::GetRHI(); if (SceneColorCopyTexture) { BasePassParameters.SceneColorCopyTexture = SceneColorCopyTexture; } BasePassParameters.EyeAdaptationTexture = GetEyeAdaptationTexture(GraphBuilder, View); BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRHI(); BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState::GetRHI(); OIT::SetOITParameters(GraphBuilder, View, BasePassParameters.OIT, OITData); return GraphBuilder.CreateUniformBuffer(&BasePassParameters); } TRDGUniformBufferRef CreateTranslucentBasePassUniformBuffer( FRDGBuilder& GraphBuilder, const FScene* Scene, const FViewInfo& View, const int32 ViewIndex, const FTranslucencyLightingVolumeTextures& TranslucencyLightingVolumeTextures, FRDGTextureRef SceneColorCopyTexture, const ESceneTextureSetupMode SceneTextureSetupMode, bool bLumenGIEnabled) { FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_None); return CreateTranslucentBasePassUniformBuffer( GraphBuilder, Scene, View, ViewIndex, TranslucencyLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData); } static FViewShaderParameters GetSeparateTranslucencyViewParameters(const FViewInfo& View, FIntPoint TextureExtent, float ViewportScale, ETranslucencyPass::Type TranslucencyPass) { FViewShaderParameters ViewParameters; const bool bIsPostMotionBlur = (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur); if (ViewportScale == 1.0f && !bIsPostMotionBlur) { // We can use the existing view uniform buffers if no downsampling is required and is not in the post-motionblur pass ViewParameters = View.GetShaderParameters(); } else if (bIsPostMotionBlur) { // Full-scale post-motionblur pass FViewUniformShaderParameters ViewUniformParameters; SetupPostMotionBlurTranslucencyViewParameters(View, ViewUniformParameters); ViewParameters.View = TUniformBufferRef::CreateUniformBufferImmediate(ViewUniformParameters, UniformBuffer_SingleFrame); if (const FViewInfo* InstancedView = View.GetInstancedView()) { SetupPostMotionBlurTranslucencyViewParameters(*InstancedView, ViewUniformParameters); ViewParameters.InstancedView = TUniformBufferRef::CreateUniformBufferImmediate( reinterpret_cast(ViewUniformParameters), UniformBuffer_SingleFrame); } } else { // Downsampled post-DOF or post-motionblur pass FViewUniformShaderParameters DownsampledTranslucencyViewParameters; SetupDownsampledTranslucencyViewParameters( View, TextureExtent, GetScaledRect(View.ViewRect, ViewportScale), TranslucencyPass, DownsampledTranslucencyViewParameters); ViewParameters.View = TUniformBufferRef::CreateUniformBufferImmediate(DownsampledTranslucencyViewParameters, UniformBuffer_SingleFrame); if (const FViewInfo* InstancedView = View.GetInstancedView()) { SetupDownsampledTranslucencyViewParameters( *InstancedView, TextureExtent, GetScaledRect(InstancedView->ViewRect, ViewportScale), TranslucencyPass, DownsampledTranslucencyViewParameters); ViewParameters.InstancedView = TUniformBufferRef::CreateUniformBufferImmediate( reinterpret_cast(DownsampledTranslucencyViewParameters), UniformBuffer_SingleFrame); } } return ViewParameters; } static void RenderViewTranslucencyInner( FRHICommandListImmediate& RHICmdList, const FSceneRenderer& SceneRenderer, const FViewInfo& View, const FScreenPassTextureViewport Viewport, const float ViewportScale, ETranslucencyPass::Type TranslucencyPass, FRDGParallelCommandListSet* ParallelCommandListSet, const FInstanceCullingDrawParams& InstanceCullingDrawParams) { FMeshPassProcessorRenderState DrawRenderState; if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur) { // No depth test in post-motionblur translucency DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } else { DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } SceneRenderer.SetStereoViewport(RHICmdList, View, ViewportScale); if (!View.Family->UseDebugViewPS()) { QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask); const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass); View.ParallelMeshDrawCommandPasses[MeshPass].DispatchDraw(ParallelCommandListSet, RHICmdList, &InstanceCullingDrawParams); } if (IsMainTranslucencyPass(TranslucencyPass)) { if (ParallelCommandListSet) { ParallelCommandListSet->SetStateOnCommandList(RHICmdList); } View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::Translucent, SDPG_World); View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::Translucent, SDPG_Foreground); // editor and debug rendering if (View.bHasTranslucentViewMeshElements) { { QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_World); DrawDynamicMeshPass(View, RHICmdList, [&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext) { FBasePassMeshProcessor PassMeshProcessor( View.Family->Scene->GetRenderScene(), View.GetFeatureLevel(), &View, DrawRenderState, DynamicMeshPassContext, FBasePassMeshProcessor::EFlags::CanUseDepthStencil, TranslucencyPass); const uint64 DefaultBatchElementMask = ~0ull; for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++) { const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex]; PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr); } }); } { QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_Foreground); DrawDynamicMeshPass(View, RHICmdList, [&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext) { FBasePassMeshProcessor PassMeshProcessor( View.Family->Scene->GetRenderScene(), View.GetFeatureLevel(), &View, DrawRenderState, DynamicMeshPassContext, FBasePassMeshProcessor::EFlags::CanUseDepthStencil, TranslucencyPass); const uint64 DefaultBatchElementMask = ~0ull; for (int32 MeshIndex = 0; MeshIndex < View.TopViewMeshElements.Num(); MeshIndex++) { const FMeshBatch& MeshBatch = View.TopViewMeshElements[MeshIndex]; PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr); } }); } } if (ParallelCommandListSet) { RHICmdList.EndRenderPass(); } } } BEGIN_SHADER_PARAMETER_STRUCT(FTranslucentBasePassParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View) SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCapture) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FTranslucentBasePassUniformParameters, BasePass) SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams) SHADER_PARAMETER_STRUCT_INCLUDE(FVirtualShadowMapSamplingParameters, VirtualShadowMapSamplingParameters) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static void RenderTranslucencyViewInner( FRDGBuilder& GraphBuilder, const FSceneRenderer& SceneRenderer, FViewInfo& View, FScreenPassTextureViewport Viewport, float ViewportScale, FRDGTextureMSAA SceneColorTexture, ERenderTargetLoadAction SceneColorLoadAction, FRDGTextureRef SceneDepthTexture, TRDGUniformBufferRef BasePassParameters, ETranslucencyPass::Type TranslucencyPass, bool bResolveColorTexture, bool bRenderInParallel, FInstanceCullingManager& InstanceCullingManager) { if (!View.ShouldRenderView()) { return; } if (SceneColorLoadAction == ERenderTargetLoadAction::EClear) { AddClearRenderTargetPass(GraphBuilder, SceneColorTexture.Target); } View.BeginRenderView(); FTranslucentBasePassParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->View = GetSeparateTranslucencyViewParameters(View, Viewport.Extent, ViewportScale, TranslucencyPass); PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer; PassParameters->BasePass = BasePassParameters; PassParameters->VirtualShadowMapSamplingParameters = SceneRenderer.ActiveViewFamily->VirtualShadowMapArray.GetSamplingParameters(GraphBuilder); PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, ERenderTargetLoadAction::ELoad); if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur) { PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite); } PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, *SceneRenderer.ActiveViewFamily, nullptr); PassParameters->RenderTargets.ResolveRect = FResolveRect(Viewport.Rect); const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass); View.ParallelMeshDrawCommandPasses[MeshPass].BuildRenderingCommands(GraphBuilder, SceneRenderer.Scene->GPUScene, PassParameters->InstanceCullingDrawParams); if (bRenderInParallel) { GraphBuilder.AddPass( RDG_EVENT_NAME("Translucency(%s Parallel) %dx%d", TranslucencyPassToString(TranslucencyPass), int32(View.ViewRect.Width() * ViewportScale), int32(View.ViewRect.Height() * ViewportScale)), PassParameters, ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass, [&SceneRenderer, &View, PassParameters, ViewportScale, Viewport, TranslucencyPass](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList) { FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_Translucency), SceneRenderer, View, FParallelCommandListBindings(PassParameters), ViewportScale); RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, &ParallelCommandListSet, PassParameters->InstanceCullingDrawParams); }); } else { GraphBuilder.AddPass( RDG_EVENT_NAME("Translucency(%s) %dx%d", TranslucencyPassToString(TranslucencyPass), int32(View.ViewRect.Width() * ViewportScale), int32(View.ViewRect.Height() * ViewportScale)), PassParameters, ERDGPassFlags::Raster, [&SceneRenderer, &View, ViewportScale, Viewport, TranslucencyPass, PassParameters](FRHICommandListImmediate& RHICmdList) { RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, nullptr, PassParameters->InstanceCullingDrawParams); }); } if (bResolveColorTexture) { AddResolveSceneColorPass(GraphBuilder, View, SceneColorTexture); } } void FDeferredShadingSceneRenderer::RenderTranslucencyInner( FRDGBuilder& GraphBuilder, const FMinimalSceneTextures& SceneTextures, const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures, FTranslucencyPassResourcesMap* OutTranslucencyResourceMap, FRDGTextureMSAA SharedDepthTexture, ETranslucencyView ViewsToRender, FRDGTextureRef SceneColorCopyTexture, ETranslucencyPass::Type TranslucencyPass, FInstanceCullingManager& InstanceCullingManager) { if (!ShouldRenderTranslucency(TranslucencyPass)) { return; } RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsTranslucencyWaitForTasksEnabled()); const bool bIsModulate = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate; const bool bDepthTest = TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur; const bool bRenderInParallel = IsParallelTranslucencyEnabled(); const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale < 1.0f; const bool bRenderInSeparateTranslucency = IsSeparateTranslucencyEnabled(TranslucencyPass, SeparateTranslucencyDimensions.Scale); // Can't reference scene color in scene textures. Scene color copy is used instead. ESceneTextureSetupMode SceneTextureSetupMode = ESceneTextureSetupMode::All; EnumRemoveFlags(SceneTextureSetupMode, ESceneTextureSetupMode::SceneColor); if (bRenderInSeparateTranslucency) { // Create resources shared by each view (each view data is tiled into each of the render target resources) FRDGTextureMSAA SharedColorTexture = CreatePostDOFTranslucentTexture(GraphBuilder, TranslucencyPass, SeparateTranslucencyDimensions, bIsModulate, ShaderPlatform); for (int32 ViewIndex = 0, NumProcessedViews = 0; ViewIndex < Views.Num(); ++ViewIndex, ++NumProcessedViews) { FViewInfo& View = Views[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender)) { continue; } RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); FIntRect ScaledViewRect = GetScaledRect(View.ViewRect, SeparateTranslucencyDimensions.Scale); const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); const bool bCompositeBackToSceneColor = IsMainTranslucencyPass(TranslucencyPass) || EnumHasAnyFlags(TranslucencyView, ETranslucencyView::UnderWater); const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen; /** Separate translucency color is either composited immediately or later during post processing. If done immediately, it's because the view doesn't support * compositing (e.g. we're rendering an underwater view) or because we're downsampling the main translucency pass. In this case, we use a local set of * textures instead of the external ones passed in. */ FRDGTextureMSAA SeparateTranslucencyColorTexture = SharedColorTexture; // NOTE: No depth test on post-motionblur translucency FRDGTextureMSAA SeparateTranslucencyDepthTexture; if (bDepthTest) { SeparateTranslucencyDepthTexture = SharedDepthTexture; } const ERenderTargetLoadAction SeparateTranslucencyColorLoadAction = NumProcessedViews == 0 || View.Family->bMultiGPUForkAndJoin ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad; FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_SeperateTranslucency); RenderTranslucencyViewInner( GraphBuilder, *this, View, SeparateTranslucencyViewport, SeparateTranslucencyDimensions.Scale, SeparateTranslucencyColorTexture, SeparateTranslucencyColorLoadAction, SeparateTranslucencyDepthTexture.Target, CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData), TranslucencyPass, !bCompositeBackToSceneColor, bRenderInParallel, InstanceCullingManager); { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); TranslucencyPassResources.ViewRect = ScaledViewRect; TranslucencyPassResources.ColorTexture = SharedColorTexture; TranslucencyPassResources.DepthTexture = SharedDepthTexture; } if (OITData.PassType & OITPass_SeperateTranslucency) { OIT::AddOITComposePass(GraphBuilder, View, OITData, SeparateTranslucencyColorTexture.Target); } if (bCompositeBackToSceneColor) { FRDGTextureRef SeparateTranslucencyDepthResolve = nullptr; FRDGTextureRef SceneDepthResolve = nullptr; if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur) { ::AddResolveSceneDepthPass(GraphBuilder, View, SeparateTranslucencyDepthTexture); SeparateTranslucencyDepthResolve = SeparateTranslucencyDepthTexture.Resolve; SceneDepthResolve = SceneTextures.Depth.Resolve; } FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); FTranslucencyComposition TranslucencyComposition; TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::ComposeToExistingSceneColor; TranslucencyComposition.SceneColor = FScreenPassTexture(SceneTextures.Color.Target, View.ViewRect); TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect); TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect); FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass( GraphBuilder, View, TranslucencyPassResources); ensure(View.ViewRect == UpscaledTranslucency.ViewRect); ensure(UpscaledTranslucency.Texture == SceneTextures.Color.Target); //Invalidate. TranslucencyPassResources = FTranslucencyPassResources(); } else { if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate) { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF); ensure(TranslucencyPassResources.ViewRect == ScaledViewRect); ensure(TranslucencyPassResources.DepthTexture == SharedDepthTexture); TranslucencyPassResources.ColorModulateTexture = SharedColorTexture; } else { check(!bIsModulate); } } ++NumProcessedViews; } } else { for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { FViewInfo& View = Views[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender)) { continue; } RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); const ERenderTargetLoadAction SceneColorLoadAction = ERenderTargetLoadAction::ELoad; const FScreenPassTextureViewport Viewport(SceneTextures.Color.Target, View.ViewRect); const float ViewportScale = 1.0f; const bool bResolveColorTexture = false; const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen; FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_RegularTranslucency); RenderTranslucencyViewInner( GraphBuilder, *this, View, Viewport, ViewportScale, SceneTextures.Color, SceneColorLoadAction, SceneTextures.Depth.Target, CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData), TranslucencyPass, bResolveColorTexture, bRenderInParallel, InstanceCullingManager); if (OITData.PassType & OITPass_RegularTranslucency) { OIT::AddOITComposePass(GraphBuilder, View, OITData, SceneTextures.Color.Target); } } } } void FDeferredShadingSceneRenderer::RenderTranslucency( FRDGBuilder& GraphBuilder, const FMinimalSceneTextures& SceneTextures, const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures, FTranslucencyPassResourcesMap* OutTranslucencyResourceMap, ETranslucencyView ViewsToRender, FInstanceCullingManager& InstanceCullingManager) { if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater)) { return; } RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency); DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution); FRDGTextureRef SceneColorCopyTexture = nullptr; if (EnumHasAnyFlags(ViewsToRender, ETranslucencyView::AboveWater)) { SceneColorCopyTexture = AddCopySceneColorPass(GraphBuilder, Views, SceneTextures.Color); } const auto ShouldRenderView = [&](const FViewInfo& View, ETranslucencyView TranslucencyView) { return View.ShouldRenderView() && EnumHasAnyFlags(TranslucencyView, ViewsToRender); }; // Create a shared depth texture at the correct resolution. FRDGTextureMSAA SharedDepthTexture; const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale != 1.0f; if (bIsScalingTranslucency) { const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D( SeparateTranslucencyDimensions.Extent, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_DepthStencilTargetable | TexCreate_ShaderResource, 1, SeparateTranslucencyDimensions.NumSamples); SharedDepthTexture = CreateTextureMSAA( GraphBuilder, Desc, TEXT("Translucency.Depth"), GFastVRamConfig.SeparateTranslucencyModulate); // TODO: this should be SeparateTranslucency, but is what the code was doing // Downscale the depth buffer for each individual view, but shared accross all translucencies. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { FViewInfo& View = Views[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!ShouldRenderView(View, TranslucencyView)) { continue; } const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); AddDownsampleDepthPass( GraphBuilder, View, FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect), FScreenPassRenderTarget(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect, ViewIndex == 0 ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad), EDownsampleDepthFilter::Point); } } else { // Uses the existing depth buffer for depth testing the translucency. SharedDepthTexture = SceneTextures.Depth; } if (ActiveViewFamily->AllowTranslucencyAfterDOF()) { RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_StandardTranslucency, InstanceCullingManager); if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucentBeforeTranslucentAfterDOF) { RenderHairComposition(GraphBuilder, Views, SceneTextures.Color.Target, SceneTextures.Depth.Target); } RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOF, InstanceCullingManager); RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate, InstanceCullingManager); RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterMotionBlur, InstanceCullingManager); } else // Otherwise render translucent primitives in a single bucket. { RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_AllTranslucency, InstanceCullingManager); } bool bUpscalePostDOFTranslucency = true; FRDGTextureRef SharedUpscaledPostDOFTranslucencyColor = nullptr; if (bUpscalePostDOFTranslucency) { const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D( SceneTextures.Color.Resolve->Desc.Extent, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource); SharedUpscaledPostDOFTranslucencyColor = GraphBuilder.CreateTexture( Desc, TEXT("Translucency.PostDOF.UpscaledColor")); } // Upscale to full res. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { FViewInfo& View = Views[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!ShouldRenderView(View, TranslucencyView)) { continue; } // Upscale the responsive AA into original depth buffer. bool bUpscaleResponsiveAA = ( IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod) && SharedDepthTexture.Target != SceneTextures.Depth.Target); if (bUpscaleResponsiveAA) { const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); AddUpsampleResponsiveAAPass( GraphBuilder, View, FScreenPassTexture(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect), /* OutputDepthTexture = */ SceneTextures.Depth.Target); } FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF); if (SharedUpscaledPostDOFTranslucencyColor && TranslucencyPassResources.IsValid() && TranslucencyPassResources.ViewRect.Size() != View.ViewRect.Size() && ITemporalUpscaler::GetMainTAAPassConfig(View) != EMainTAAPassConfig::TSR) { FTranslucencyComposition TranslucencyComposition; TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::UpscaleOnly; TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect); TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect); FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass( GraphBuilder, View, TranslucencyPassResources); TranslucencyPassResources.ViewRect = UpscaledTranslucency.ViewRect; TranslucencyPassResources.ColorTexture = FRDGTextureMSAA(UpscaledTranslucency.Texture); TranslucencyPassResources.DepthTexture = FRDGTextureMSAA(); } } }