// 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 "Lumen/RayTracedTranslucency.h" #include "VirtualShadowMaps/VirtualShadowMapArray.h" #include "Substrate/Substrate.h" #include "HairStrands/HairStrandsUtils.h" #include "PixelShaderUtils.h" #include "OIT/OIT.h" #include "OIT/OITParameters.h" #include "DynamicResolutionState.h" #include "PostProcess/SceneRenderTargets.h" #include "PostProcess/TemporalAA.h" #include "BlueNoise.h" DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQueryFence Wait"), STAT_TranslucencyTimestampQueryFence_Wait, STATGROUP_SceneRendering); DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQuery Wait"), STAT_TranslucencyTimestampQuery_Wait, STATGROUP_SceneRendering); DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucency GPU Time (MS)"), STAT_TranslucencyGPU, STATGROUP_SceneRendering); DEFINE_GPU_DRAWCALL_STAT(Translucency); // Forward declarations bool ShouldRenderVolumetricCloud(const FScene* Scene, const FEngineShowFlags& EngineShowFlags); bool IsVSMTranslucentHighQualityEnabled(); 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 CVarTranslucencyMaxScreenPercentage( TEXT("r.Translucency.DynamicRes.MaxScreenPercentage"), DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultMaxResolutionFraction), TEXT("Maximal 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); static TAutoConsoleVariable CVarTranslucencyUpperBoundQuantization( TEXT("r.Translucency.DynamicRes.UpperBoundQuantization"), DynamicRenderScaling::FHeuristicSettings::kDefaultUpperBoundQuantization, TEXT("Quantization step count to use for upper bound screen percentage.\n") TEXT("If non-zero, rendertargets will be resized based on the dynamic resolution fraction, saving GPU time during clears and resolves.\n") TEXT("Only recommended for use with the transient allocator (on supported platforms) with a large transient texture cache (e.g RHI.TransientAllocator.TextureCacheSize=512)"), ECVF_RenderThreadSafe | ECVF_Default); static TAutoConsoleVariable CVarVolumetricCloudSoftBlendingDistanceOnTranslucent( TEXT("r.VolumetricCloud.SoftBlendingDistanceOnTranslucent"), 0.5, TEXT("The soft blending in distance in kilometer used to soft blend in cloud over translucent from the evaluated start depth."), ECVF_RenderThreadSafe | ECVF_Scalability); 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 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.MaxResolutionFraction = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyMaxScreenPercentage); BucketSetting.BudgetMs = CVarTranslucencyTimeBudget.GetValueOnAnyThread(); BucketSetting.ChangeThreshold = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyChangeThreshold); BucketSetting.TargetedHeadRoom = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyTargetedHeadRoomPercentage); BucketSetting.UpperBoundQuantization = CVarTranslucencyUpperBoundQuantization.GetValueOnAnyThread(); return BucketSetting; } DynamicRenderScaling::FBudget GDynamicTranslucencyResolution(TEXT("DynamicTranslucencyResolution"), &GetDynamicTranslucencyResolutionSettings); static const TCHAR* kTranslucencyPassName[] = { TEXT("BeforeDistortion"), TEXT("BeforeDistortionModulate"), TEXT("AfterDOF"), TEXT("AfterDOFModulate"), TEXT("AfterMotionBlur"), TEXT("Holdout"), TEXT("All"), }; static_assert(UE_ARRAY_COUNT(kTranslucencyPassName) == int32(ETranslucencyPass::TPT_MAX), "Fix me"); static const TCHAR* kTranslucencyColorTextureName[] = { TEXT("Translucency.BeforeDistortion.Color"), TEXT("Translucency.BeforeDistortion.Modulate"), TEXT("Translucency.AfterDOF.Color"), TEXT("Translucency.AfterDOF.Modulate"), TEXT("Translucency.AfterMotionBlur.Color"), TEXT("Translucency.Holdout.Visibility"), TEXT("Translucency.All.Color"), }; static_assert(UE_ARRAY_COUNT(kTranslucencyColorTextureName) == int32(ETranslucencyPass::TPT_MAX), "Fix me"); static const TCHAR* kTranslucencyColorTextureMultisampledName[] = { TEXT("Translucency.BeforeDistortion.ColorMS"), TEXT("Translucency.BeforeDistortion.ModulateMS"), TEXT("Translucency.AfterDOF.ColorMS"), TEXT("Translucency.AfterDOF.ModulateMS"), TEXT("Translucency.AfterMotionBlur.ColorMS"), TEXT("Translucency.Holdout.VisibilityMS"), TEXT("Translucency.All.ColorMS"), }; static_assert(UE_ARRAY_COUNT(kTranslucencyColorTextureMultisampledName) == UE_ARRAY_COUNT(kTranslucencyColorTextureName), "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_TranslucencyStandard: TranslucencyMeshPass = EMeshPass::TranslucencyStandard; break; case ETranslucencyPass::TPT_TranslucencyStandardModulate: TranslucencyMeshPass = EMeshPass::TranslucencyStandardModulate; 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_TranslucencyHoldout: TranslucencyMeshPass = EMeshPass::TranslucencyHoldout; break; case ETranslucencyPass::TPT_AllTranslucency: TranslucencyMeshPass = EMeshPass::TranslucencyAll; break; } check(TranslucencyMeshPass != EMeshPass::Num); return TranslucencyMeshPass; } ETranslucencyView GetTranslucencyView(const FViewInfo& View) { if (ShouldRenderRayTracingTranslucency(View) || RayTracedTranslucency::IsEnabled(View)) { return ETranslucencyView::RayTracing; } 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_TranslucencyStandard; } static bool IsParallelTranslucencyEnabled() { return GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread(); } 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_TranslucencyStandardModulate || 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 FSceneRenderer& SceneRenderer) { float TranslucencyResolutionFraction = FMath::Clamp(CVarSeparateTranslucencyScreenPercentage.GetValueOnRenderThread() / 100.0f, 0.0f, 1.0f); float MaxTranslucencyResolutionFraction = TranslucencyResolutionFraction; if (GDynamicTranslucencyResolution.GetSettings().IsEnabled()) { TranslucencyResolutionFraction = SceneRenderer.DynamicResolutionFractions[GDynamicTranslucencyResolution]; MaxTranslucencyResolutionFraction = SceneRenderer.DynamicResolutionUpperBounds[GDynamicTranslucencyResolution]; } if (CVarTranslucencyScreenPercentageBasis.GetValueOnRenderThread() == 1) { TranslucencyResolutionFraction /= SceneRenderer.DynamicResolutionFractions[GDynamicPrimaryResolutionFraction]; MaxTranslucencyResolutionFraction /= SceneRenderer.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(SceneRenderer.ViewFamily.SceneTexturesConfig.Extent, TranslucencyResolutionFraction); Dimensions.NumSamples = SceneRenderer.ViewFamily.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,bool WithAlpha = false) { 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; } FRHIBlendState* BlendState = nullptr; if (WithAlpha) { BlendState = FScreenPassPipelineState::FDefaultBlendState::GetRHI(); } else { // The original behavior sets alpha to zero. BlendState = TStaticBlendState::GetRHI(); } AddDrawScreenPass(GraphBuilder, {}, View, Viewport, Viewport, VertexShader, PixelShader, PassParameters); } } return SceneColorCopyTexture; } static void AddCopySceneColorAlphaPass(FRDGBuilder& GraphBuilder, TArrayView Views, FRDGTextureRef SourceTexture, FRDGTextureRef TargetTexture) { ERenderTargetLoadAction LoadAction = ERenderTargetLoadAction::ENoAction; RDG_EVENT_SCOPE(GraphBuilder, "CopySceneColorAlpha"); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { const FViewInfo& View = Views[ViewIndex]; if (View.IsUnderwater()) { continue; } RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); const FIntPoint SceneColorExtent = SourceTexture->Desc.Extent; const FScreenPassTextureViewport Viewport(TargetTexture, View.ViewRect); TShaderMapRef VertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); auto* PassParameters = GraphBuilder.AllocParameters(); PassParameters->View = View.ViewUniformBuffer; PassParameters->SceneColorTexture = SourceTexture; PassParameters->RenderTargets[0] = FRenderTargetBinding(TargetTexture, LoadAction); if (!View.Family->bMultiGPUForkAndJoin) { LoadAction = ERenderTargetLoadAction::ELoad; } FRHIBlendState* BlendState = TStaticBlendState::GetRHI(); AddDrawScreenPass(GraphBuilder, {}, View, Viewport, Viewport, VertexShader, PixelShader, BlendState, PassParameters); } } class FCopyBackgroundVisibilityPS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FCopyBackgroundVisibilityPS); SHADER_USE_PARAMETER_STRUCT(FCopyBackgroundVisibilityPS, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, TranslucentHoldoutPointTexture) SHADER_PARAMETER_SAMPLER(SamplerState, TranslucentHoldoutPointSampler) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() enum class EVisibilityCopyType :int32 { FromSceneColor, // Copy alpha (background visibility) of scene color to any of the rgb ToSceneColor, // Copy background visibility from any of the rgb to the alpha of an image for scene color composition. MAX }; static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } class FDimVisibilityCopyType :SHADER_PERMUTATION_ENUM_CLASS("VISIBILITY_COPY_TYPE", EVisibilityCopyType); using FPermutationDomain = TShaderPermutationDomain; }; 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(FScreenTransform, SeparateTranslucencyUVToViewportUV) SHADER_PARAMETER(FScreenTransform, ViewportUVToSeparateTranslucencyUV) SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMin) SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMax) SHADER_PARAMETER(FVector2f, SeparateTranslucencyExtentInverse) SHADER_PARAMETER(int32, bLensDistortion) SHADER_PARAMETER(int32, bPassthroughAlpha) SHADER_PARAMETER_RDG_TEXTURE_SRV(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_RDG_TEXTURE(Texture2D, UndistortingDisplacementTexture) SHADER_PARAMETER_SAMPLER(SamplerState, UndistortingDisplacementSampler) 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(FCopyBackgroundVisibilityPS, "/Engine/Private/ComposeSeparateTranslucency.usf", "CopyBackgroundVisibilityPS", SF_Pixel); IMPLEMENT_GLOBAL_SHADER(FComposeSeparateTranslucencyPS, "/Engine/Private/ComposeSeparateTranslucency.usf", "MainPS", SF_Pixel); IMPLEMENT_GLOBAL_SHADER(FTranslucencyUpsampleResponsiveAAPS, "/Engine/Private/TranslucencyUpsampling.usf", "UpsampleResponsiveAAPS", SF_Pixel); static void AddCopyBackgroundVisibilityPass( FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef CopySource, FRDGTextureRef CopyDestination, FIntRect CopyRect, FCopyBackgroundVisibilityPS::EVisibilityCopyType VisibilityCopyType) { typedef FCopyBackgroundVisibilityPS SHADER; SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters(); { PassParameters->ViewUniformBuffer = View.ViewUniformBuffer; PassParameters->TranslucentHoldoutPointTexture = CopySource; PassParameters->TranslucentHoldoutPointSampler = TStaticSamplerState::GetRHI(); PassParameters->RenderTargets[0] = FRenderTargetBinding(CopyDestination, ERenderTargetLoadAction::ENoAction); } SHADER::FPermutationDomain PixelShaderPermutationVector; PixelShaderPermutationVector.Set(VisibilityCopyType); TShaderMapRef PixelShader(View.ShaderMap, PixelShaderPermutationVector); FRHIBlendState* BlendState = TStaticBlendState::GetRHI(); FPixelShaderUtils::AddFullscreenPass( GraphBuilder, View.ShaderMap, RDG_EVENT_NAME( "%s(%s) %dx%d", TEXT("CopyBackgroundVisibility"), TEXT("Holdout"), CopyRect.Width(), CopyRect.Height()), PixelShader, PassParameters, CopyRect, BlendState); } 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 FScreenPassTexture(SceneColor); } ensure(TranslucencyTextures.Pass != ETranslucencyPass::TPT_MAX); 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 FScreenPassTexture(SceneColor); } SeparateTranslucencyTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy); } bool bPassthroughAlpha = IsPrimitiveAlphaHoldoutEnabled(View); const TCHAR* OpName = nullptr; FRHIBlendState* BlendState = nullptr; FRDGTextureRef NewSceneColor = nullptr; if (Operation == EOperation::UpscaleOnly) { check(!SceneColor.IsValid()); //ensure(!TranslucencyTextures.ColorModulateTexture.IsValid()); // It is valid to have a valid TranslucencyTextures.ColorModulateTexture in "UpscaleTranslucency". Since it can will be upscaled later in the ComposeTranslucencyToNewSceneColor pass (apply onto scene color with added translucency color on top). 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.TextureSRV->Desc.Texture->Desc.Flags & TexCreate_RenderTargetable); NewSceneColor = SceneColor.TextureSRV->Desc.Texture; } else if (Operation == EOperation::ComposeToNewSceneColor) { check(SceneColor.IsValid()); OpName = TEXT("ComposeTranslucencyToNewSceneColor"); FRDGTextureDesc OutputDesc = FRDGTextureDesc::Create2D( OutputViewport.Extent, OutputPixelFormat != PF_Unknown ? OutputPixelFormat : SceneColor.TextureSRV->Desc.Texture->Desc.Format, FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource); NewSceneColor = GraphBuilder.CreateTexture( OutputDesc, bPostMotionBlur ? TEXT("PostMotionBlurTranslucency.SceneColor") : TEXT("PostDOFTranslucency.SceneColor")); } else if (Operation == EOperation::ComposeToSceneColorAlpha) { check(SceneColor.IsValid()); // Now we copy any of RGB channel(background visibility) to alpha channel so we can compose against the holdout value of the background. FRDGTextureRef ResolvedTranslucentHoldout = GraphBuilder.CreateTexture(SeparateTranslucencyTexture->Desc,TEXT("Translucency.Holdout.Resolved")); AddCopyBackgroundVisibilityPass(GraphBuilder, View, SeparateTranslucencyTexture, ResolvedTranslucentHoldout, TranslucencyTextures.ViewRect, FCopyBackgroundVisibilityPS::EVisibilityCopyType::ToSceneColor); SeparateTranslucencyTexture = ResolvedTranslucentHoldout; OpName = TEXT("ComposeToSceneColorAlpha"); // Keep the color of the target, but override the alpha channel // Req: Alpha stores the background visibility of the holdout. // If the background is opaque, it is 1, otherwise 0, use Max operator to clamp. BlendState = TStaticBlendState::GetRHI(); ensure(SceneColor.TextureSRV->Desc.Texture->Desc.Flags & TexCreate_RenderTargetable); NewSceneColor = SceneColor.TextureSRV->Desc.Texture; bPassthroughAlpha = false; } else { unimplemented(); } RDG_EVENT_SCOPE_STAT(GraphBuilder, Translucency, "%s", OpName); RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency); DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution); 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->SeparateTranslucencyUVToViewportUV = FScreenTransform::ChangeTextureBasisFromTo( TranslucencyViewport, FScreenTransform::ETextureBasis::TextureUV, FScreenTransform::ETextureBasis::ViewportUV); PassParameters->ViewportUVToSeparateTranslucencyUV = 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.TextureSRV : GraphBuilder.CreateSRV(FRDGTextureSRVDesc(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->UndistortingDisplacementTexture = GSystemTextures.GetBlackDummy(GraphBuilder); PassParameters->UndistortingDisplacementSampler = TStaticSamplerState::GetRHI(); PassParameters->bLensDistortion = LensDistortionLUT.IsEnabled(); PassParameters->bPassthroughAlpha = bPassthroughAlpha; if (LensDistortionLUT.IsEnabled()) { PassParameters->UndistortingDisplacementTexture = LensDistortionLUT.UndistortingDisplacementTexture; } PassParameters->ViewUniformBuffer = View.ViewUniformBuffer; if (Operation == EOperation::ComposeToExistingSceneColor || Operation == EOperation::ComposeToSceneColorAlpha) { 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[FMath::Clamp(int32(TranslucencyTextures.Pass), 0, int32(ETranslucencyPass::TPT_MAX) - 1)], bApplyModulateOnly ? TEXT(" ModulateOnly") : TEXT(""), DepthUpscampling ? TEXT(" DepthUpsampling") : 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](FRDGAsyncTask, 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 ViewFamily.EngineShowFlags.Translucency && !ViewFamily.EngineShowFlags.VisualizeLightCulling && !ViewFamily.UseDebugViewPS(); } bool FSceneRenderer::ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass, TArrayView InViews) { extern int32 GLightShaftRenderAfterDOF; // Change this condition to control where simple elements should be rendered. if (IsMainTranslucencyPass(TranslucencyPass)) { for (const FViewInfo& View : InViews) { 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_TranslucencyStandard. if (GLightShaftRenderAfterDOF && TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF) { return true; } for (const FViewInfo& View : InViews) { if (View.TranslucentPrimCount.Num(TranslucencyPass) > 0) { return true; } } return false; } FScreenPassTextureViewport FSeparateTranslucencyDimensions::GetInstancedStereoViewport(const FViewInfo& View) const { FIntRect ViewRect = View.ViewRectWithSecondaryViews; 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(); FViewMatrices ModifiedPrevViewViewMatrices = View.PrevViewInfo.ViewMatrices; ModifiedPrevViewViewMatrices.HackRemoveTemporalAAProjectionJitter(); Parameters = *View.CachedViewUniformShaderParameters; View.SetupUniformBufferParameters(ModifiedViewMatrices, ModifiedPrevViewViewMatrices, VolumeBounds, TVC_MAX, Parameters); } const FRDGTextureDesc GetPostDOFTranslucentTextureDesc( ETranslucencyPass::Type TranslucencyPass, const FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions, bool bIsModulate, EShaderPlatform ShaderPlatform) { const bool bNeedUAV = SeparateTranslucencyDimensions.NumSamples == 1 && OIT::IsSortedPixelsEnabled(ShaderPlatform); FClearValueBinding ClearValueBinding = bIsModulate ? FClearValueBinding::White : FClearValueBinding::Black; if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyHoldout) { ClearValueBinding = FClearValueBinding::Black; } return 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); } FRDGTextureMSAA CreatePostDOFTranslucentTexture( FRDGBuilder& GraphBuilder, ETranslucencyPass::Type TranslucencyPass, const FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions, bool bIsModulate, EShaderPlatform ShaderPlatform) { const FRDGTextureDesc Desc = GetPostDOFTranslucentTextureDesc(TranslucencyPass, SeparateTranslucencyDimensions, bIsModulate, ShaderPlatform); return CreateTextureMSAA( GraphBuilder, Desc, kTranslucencyColorTextureMultisampledName[int32(TranslucencyPass)], 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(); FBox VolumeBounds[TVC_MAX]; View.SetupUniformBufferParameters(ViewMatrices, PrevViewMatrices, VolumeBounds, TVC_MAX, DownsampledTranslucencyViewParameters); } // 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, ETranslucencyPass::Type TranslucencyPass) { FTranslucentBasePassUniformParameters& BasePassParameters = *GraphBuilder.AllocParameters(); const auto GetRDG = [&](const TRefCountPtr& PooledRenderTarget, ERDGTextureFlags Flags = ERDGTextureFlags::None) { return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, Flags); }; SetupSharedBasePassParameters(GraphBuilder, View, ViewIndex, bLumenGIEnabled, BasePassParameters.Shared); SetupSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), View.FeatureLevel, SceneTextureSetupMode, BasePassParameters.SceneTextures); Substrate::BindSubstrateForwardPasslUniformParameters(GraphBuilder, View, BasePassParameters.Substrate); 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 (IsHZBValid(View, EHZBType::FurthestHZB)) { BasePassParameters.HZBParameters = GetHZBParameters(GraphBuilder, View, EHZBType::FurthestHZB); FRDGTextureSRVRef PrevSceneColorTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc(SystemTextures.Black)); FIntRect PrevSceneColorViewRect = FIntRect(0, 0, 1, 1); if (View.PrevViewInfo.CustomSSRInput.IsValid()) { PrevSceneColorTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc(GetRDG(View.PrevViewInfo.CustomSSRInput.RT[0]))); PrevSceneColorViewRect = View.PrevViewInfo.CustomSSRInput.ViewportRect; PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure; } else if (View.PrevViewInfo.TemporalAAHistory.IsValid()) { FRDGTextureRef TemporalAAHistoryTexture = GetRDG(View.PrevViewInfo.TemporalAAHistory.RT[0]); PrevSceneColorTexture = GraphBuilder.CreateSRV(TemporalAAHistoryTexture->Desc.IsTextureArray() ? FRDGTextureSRVDesc::CreateForSlice(TemporalAAHistoryTexture, View.PrevViewInfo.TemporalAAHistory.OutputSliceIndex) : FRDGTextureSRVDesc(TemporalAAHistoryTexture)); PrevSceneColorViewRect = View.PrevViewInfo.TemporalAAHistory.ViewportRect; PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure; } else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid()) { PrevSceneColorTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc(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->Desc.Texture, PrevSceneColorViewRect)); BasePassParameters.PrevSceneColorBilinearUVMin = PrevSceneColorParameters.UVViewportBilinearMin; BasePassParameters.PrevSceneColorBilinearUVMax = PrevSceneColorParameters.UVViewportBilinearMax; } else { BasePassParameters.HZBParameters = GetDummyHZBParameters(GraphBuilder); BasePassParameters.PrevSceneColor = GraphBuilder.CreateSRV(FRDGTextureSRVDesc(SystemTextures.Black)); BasePassParameters.PrevSceneColorSampler = TStaticSamplerState::GetRHI(); BasePassParameters.PrevSceneColorBilinearUVMin = FVector2f(0.0f, 0.0f); BasePassParameters.PrevSceneColorBilinearUVMax = FVector2f(1.0f, 1.0f); } BasePassParameters.SoftBlendingDistanceKm = FMath::Max(0.0001f, CVarVolumetricCloudSoftBlendingDistanceOnTranslucent.GetValueOnRenderThread()); BasePassParameters.ApplyVolumetricCloudOnTransparent = 0.0f; BasePassParameters.VolumetricCloudColor = nullptr; BasePassParameters.VolumetricCloudDepth = nullptr; BasePassParameters.VolumetricCloudColorSampler = TStaticSamplerState::GetRHI(); BasePassParameters.VolumetricCloudDepthSampler = TStaticSamplerState::GetRHI(); const bool bVRTValid = View.ViewState != nullptr && View.ViewState->VolumetricCloudRenderTarget.IsValid(); if (bVRTValid && IsVolumetricRenderTargetEnabled() && ShouldRenderVolumetricCloud(Scene, View.Family->EngineShowFlags)) { int32 VRTMode = View.ViewState->VolumetricCloudRenderTarget.GetMode(); if (VRTMode == 1 || VRTMode == 3) { FRDGTextureRef VolumetricReconstructRT = View.ViewState->VolumetricCloudRenderTarget.GetOrCreateVolumetricTracingRT(GraphBuilder); if (VolumetricReconstructRT) { BasePassParameters.VolumetricCloudColor = VolumetricReconstructRT; BasePassParameters.VolumetricCloudDepth = View.ViewState->VolumetricCloudRenderTarget.GetOrCreateVolumetricTracingRTDepth(GraphBuilder); BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f; BasePassParameters.VolumetricCloudColorUVScale = View.ViewState->VolumetricCloudRenderTarget.GetVolumetricTracingUVScale(); BasePassParameters.VolumetricCloudColorUVMax = View.ViewState->VolumetricCloudRenderTarget.GetVolumetricTracingUVMax(); } } else { TRefCountPtr VolumetricReconstructRT = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRT(); if (VolumetricReconstructRT.IsValid()) { TRefCountPtr VolumetricReconstructRTDepth = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRTDepth(); BasePassParameters.VolumetricCloudColor = GraphBuilder.RegisterExternalTexture(VolumetricReconstructRT); BasePassParameters.VolumetricCloudDepth = GraphBuilder.RegisterExternalTexture(VolumetricReconstructRTDepth); BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f; BasePassParameters.VolumetricCloudColorUVScale = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructUVScale(); BasePassParameters.VolumetricCloudColorUVMax = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructUVMax(); } } } if (BasePassParameters.VolumetricCloudColor == nullptr) { BasePassParameters.VolumetricCloudColor = GSystemTextures.GetBlackAlphaOneDummy(GraphBuilder); BasePassParameters.VolumetricCloudDepth = GSystemTextures.GetBlackDummy(GraphBuilder); } 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.GetLumenTranslucencyGIVolume(), 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.EyeAdaptationBuffer = GraphBuilder.CreateSRV(GetEyeAdaptationBuffer(GraphBuilder, View)); BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRHI(); BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState::GetRHI(); OIT::SetOITParameters(GraphBuilder, View, BasePassParameters.OIT, OITData); // Only use blue noise resources if VSM quality is set to high if (IsVSMTranslucentHighQualityEnabled() || IsTranslucencyLightingVolumeUsingBlueNoise()) { BasePassParameters.BlueNoise = GetBlueNoiseParameters(); } else { BasePassParameters.BlueNoise = GetBlueNoiseDummyParameters(); } BasePassParameters.AVSM = HeterogeneousVolumes::GetAdaptiveVolumetricCameraMapParameters(GraphBuilder, View.ViewState); // Translucency pass for holdout BasePassParameters.TranslucencyPass = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyHoldout ? 1 : 0; 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, ETranslucencyPass::Type TranslucencyPass) { FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_None); return CreateTranslucentBasePassUniformBuffer( GraphBuilder, Scene, View, ViewIndex, TranslucencyLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData, TranslucencyPass); } 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 (ViewportScale == 1.0f && bIsPostMotionBlur) { // Full-scale post-motionblur pass FViewUniformShaderParameters ViewUniformParameters; SetupPostMotionBlurTranslucencyViewParameters(View, ViewUniformParameters); ViewParameters.View = TUniformBufferRef::CreateUniformBufferImmediate(ViewUniformParameters, UniformBuffer_SingleFrame); if (View.bShouldBindInstancedViewUB) { FInstancedViewUniformShaderParameters LocalInstancedViewUniformShaderParameters; InstancedViewParametersUtils::CopyIntoInstancedViewParameters(LocalInstancedViewUniformShaderParameters, ViewUniformParameters, 0); if (const FViewInfo* InstancedView = View.GetInstancedView()) { SetupPostMotionBlurTranslucencyViewParameters(*InstancedView, ViewUniformParameters); InstancedViewParametersUtils::CopyIntoInstancedViewParameters(LocalInstancedViewUniformShaderParameters, ViewUniformParameters, 1); } ViewParameters.InstancedView = TUniformBufferRef::CreateUniformBufferImmediate( reinterpret_cast(LocalInstancedViewUniformShaderParameters), 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 (View.bShouldBindInstancedViewUB) { FInstancedViewUniformShaderParameters LocalInstancedViewUniformShaderParameters; InstancedViewParametersUtils::CopyIntoInstancedViewParameters(LocalInstancedViewUniformShaderParameters, DownsampledTranslucencyViewParameters, 0); if (const FViewInfo* InstancedView = View.GetInstancedView()) { SetupDownsampledTranslucencyViewParameters( *InstancedView, TextureExtent, GetScaledRect(InstancedView->ViewRect, ViewportScale), TranslucencyPass, DownsampledTranslucencyViewParameters); InstancedViewParametersUtils::CopyIntoInstancedViewParameters(LocalInstancedViewUniformShaderParameters, DownsampledTranslucencyViewParameters, 1); } ViewParameters.InstancedView = TUniformBufferRef::CreateUniformBufferImmediate( reinterpret_cast(LocalInstancedViewUniformShaderParameters ), UniformBuffer_SingleFrame); } } return ViewParameters; } 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, int32 ViewIndex, 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; // Custom render passes run early in the frame before VSMs have been processed. The VSM uniforms will be dummy at that point in the frame, so it doesn't matter which // ViewIndex in the VirtualShadowMapArray is referenced, but it needs to be an index that's not out of range of the array. To handle that case, pass in an index of // zero, so it arbitrarily uses the first element. PassParameters->VirtualShadowMapSamplingParameters = SceneRenderer.VirtualShadowMapArray.GetSamplingParameters(GraphBuilder, View.CustomRenderPass == nullptr ? ViewIndex : 0); 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); } // Only apply VRS if the translucency render target is at the same scale as the internal resolution const bool bUseVRS = (ViewportScale == 1.0f); if (bUseVRS) { PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::TranslucencyAll); } PassParameters->RenderTargets.ResolveRect = FResolveRect(Viewport.Rect); const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass); if (auto* Pass = View.ParallelMeshDrawCommandPasses[MeshPass]) { Pass->BuildRenderingCommands(GraphBuilder, SceneRenderer.Scene->GPUScene, PassParameters->InstanceCullingDrawParams); if (!View.Family->UseDebugViewPS()) { if (bRenderInParallel) { GraphBuilder.AddDispatchPass( RDG_EVENT_NAME("Translucency(%s Parallel) %dx%d", TranslucencyPassToString(TranslucencyPass), int32(View.ViewRect.Width() * ViewportScale), int32(View.ViewRect.Height() * ViewportScale)), PassParameters, ERDGPassFlags::Raster, [Pass, PassParameters, ViewportScale](FRDGDispatchPassBuilder& DispatchPassBuilder) { Pass->Dispatch(DispatchPassBuilder, &PassParameters->InstanceCullingDrawParams, ViewportScale); }); } 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, [&View, Pass, PassParameters, ViewportScale](FRDGAsyncTask, FRHICommandList& RHICmdList) { FSceneRenderer::SetStereoViewport(RHICmdList, View, ViewportScale); Pass->Draw(RHICmdList, &PassParameters->InstanceCullingDrawParams); }); } } } else { InstanceCullingManager.SetDummyCullingParams(GraphBuilder, PassParameters->InstanceCullingDrawParams); } if (IsMainTranslucencyPass(TranslucencyPass) && (View.SimpleElementCollector.HasAnyPrimitives() || View.bHasTranslucentViewMeshElements)) { GraphBuilder.AddPass( RDG_EVENT_NAME("TranslucencyElements(%s) %dx%d", TranslucencyPassToString(TranslucencyPass), int32(View.ViewRect.Width() * ViewportScale), int32(View.ViewRect.Height() * ViewportScale)), PassParameters, ERDGPassFlags::Raster, [&View, TranslucencyPass, ViewportScale] (FRHICommandList& RHICmdList) { FSceneRenderer::SetStereoViewport(RHICmdList, View, ViewportScale); FMeshPassProcessorRenderState DrawRenderState; DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); 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( EMeshPass::Num, 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); } }); } if (!View.Family->EngineShowFlags.CompositeEditorPrimitives) { QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_Foreground); DrawDynamicMeshPass(View, RHICmdList, [&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext) { FBasePassMeshProcessor PassMeshProcessor( EMeshPass::Num, 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 (bResolveColorTexture) { AddResolveSceneColorPass(GraphBuilder, View, SceneColorTexture); } } void FDeferredShadingSceneRenderer::RenderTranslucencyInner( FDeferredShadingSceneRenderer& Renderer, FRDGBuilder& GraphBuilder, const FMinimalSceneTextures& SceneTextures, const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures, FTranslucencyPassResourcesMap* OutTranslucencyResourceMap, FRDGTextureMSAA SharedDepthTexture, TArray& InViews, ETranslucencyView ViewsToRender, const FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions, FRDGTextureRef SceneColorCopyTexture, ETranslucencyPass::Type TranslucencyPass, FInstanceCullingManager& InstanceCullingManager, bool bStandardTranslucentCanRenderSeparate) { if (!ShouldRenderTranslucency(TranslucencyPass, InViews)) { return; } const FScene* Scene = Renderer.Scene; const FSceneViewFamily& ViewFamily = *InViews[0].Family; const bool bIsModulate = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate || TranslucencyPass == ETranslucencyPass::TPT_TranslucencyStandardModulate; const bool bDepthTest = TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur; const bool bRenderInParallel = IsParallelTranslucencyEnabled(); const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale < 1.0f; const bool bIsStandardSeparatedTranslucency = bStandardTranslucentCanRenderSeparate && TranslucencyPass == ETranslucencyPass::TPT_TranslucencyStandard && ViewFamily.AllowStandardTranslucencySeparated(); const bool bRenderInSeparateTranslucency = IsSeparateTranslucencyEnabled(TranslucencyPass, SeparateTranslucencyDimensions.Scale) || bIsStandardSeparatedTranslucency; // Holdout rendering const bool bRenderTranslucencyHold = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyHoldout; // Can't reference scene color in scene textures. Scene color copy is used instead. ESceneTextureSetupMode SceneTextureSetupMode = ESceneTextureSetupMode::All; EnumRemoveFlags(SceneTextureSetupMode, ESceneTextureSetupMode::SceneColor); // 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, Scene->GetShaderPlatform()); for (int32 ViewIndex = 0, NumProcessedViews = 0; ViewIndex < InViews.Num(); ++ViewIndex) { FViewInfo& View = InViews[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender)) { continue; } // We run separate and composited translucent only when the view is NOT under water. // When under water, we render each translucency pass in forward on the water buffer itself. const bool bViewIsUnderWater = EnumHasAnyFlags(TranslucencyView, ETranslucencyView::UnderWater); if (bRenderInSeparateTranslucency && !bViewIsUnderWater) { RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, InViews.Num() > 1, "View%d", ViewIndex); FIntRect ScaledViewRect = GetScaledRect(View.ViewRect, SeparateTranslucencyDimensions.Scale); const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); const bool bCompositeBackToSceneColor = (IsMainTranslucencyPass(TranslucencyPass) && !bIsStandardSeparatedTranslucency); const bool bLumenGIEnabled = Renderer.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); const bool bRenderTranslucencyViewInner = OIT::IsSortedPixelsEnabled(View) ? !bIsModulate : true; if (bRenderTranslucencyViewInner) { RenderTranslucencyViewInner( GraphBuilder, Renderer, View, ViewIndex, SeparateTranslucencyViewport, SeparateTranslucencyDimensions.Scale, SeparateTranslucencyColorTexture, SeparateTranslucencyColorLoadAction, SeparateTranslucencyDepthTexture.Target, CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData, TranslucencyPass), TranslucencyPass, !bCompositeBackToSceneColor, bRenderInParallel, InstanceCullingManager); { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); TranslucencyPassResources.ViewRect = ScaledViewRect; TranslucencyPassResources.ColorTexture = SharedColorTexture; TranslucencyPassResources.DepthTexture = SharedDepthTexture; } } if (OIT::IsSortedPixelsEnabled(View) && !!(OITData.PassType & OITPass_SeperateTranslucency)) { // * If this pass it not modulate (i.e., TranslucencyPass != ETranslucencyPass::TPT_TranslucencyXXXModulate), then: // * Either the result is directly composed to the the color target. // * Or the luminance is composed to the color target, and the transmittance composed into a new allocated 'modulate' target // * If this pass is modulate (i.e., TranslucencyPass == ETranslucencyPass::TPT_TranslucencyXXXModulate), then we only redirect SharedColorTexture to the modulate target, allocated during the previous pass if (!bIsModulate) { if (bCompositeBackToSceneColor || TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur) { // Compose the final result (Luminance + Transmittance) to the color target OIT::AddOITComposePass(GraphBuilder, View, OITData, SeparateTranslucencyColorTexture.Target); } else { ETranslucencyPass::Type ModulateTranslucencyPass = ETranslucencyPass::TPT_MAX; if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyStandard) { ModulateTranslucencyPass = ETranslucencyPass::TPT_TranslucencyStandardModulate; } else if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF) { ModulateTranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterDOFModulate; } // * Compose the luminance to the color target // * Allocate a new target for the transmittance // * Compose the transmittance to the transmittance target if (TranslucencyPass != ETranslucencyPass::TPT_MAX) { FRDGTextureMSAA ModulateTexture = CreatePostDOFTranslucentTexture(GraphBuilder, ModulateTranslucencyPass, SeparateTranslucencyDimensions, true /*bIsModulate*/, Scene->GetShaderPlatform()); OIT::AddOITComposePass(GraphBuilder, View, OITData, SeparateTranslucencyColorTexture.Target, ModulateTexture.Target); FTranslucencyPassResources& ModulateTranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ModulateTranslucencyPass); ModulateTranslucencyPassResources.ViewRect = ScaledViewRect; ModulateTranslucencyPassResources.ColorTexture = nullptr; ModulateTranslucencyPassResources.ColorModulateTexture = ModulateTexture; ModulateTranslucencyPassResources.DepthTexture = SharedDepthTexture; } } } else { // Retrieve the modulate texture, which was allocated and fill-in during the previous (non-modulate) transparentcy pass. check(!bCompositeBackToSceneColor); FTranslucencyPassResources& ModulateTranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); SharedColorTexture = ModulateTranslucencyPassResources.ColorModulateTexture; ModulateTranslucencyPassResources.ViewRect = ScaledViewRect; ModulateTranslucencyPassResources.DepthTexture = SharedDepthTexture; } } 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 = FScreenPassTextureSlice::CreateFromScreenPassTexture(GraphBuilder, 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(); TranslucencyPassResources.Pass = TranslucencyPass; } 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 if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyStandardModulate) { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyStandard); ensure(TranslucencyPassResources.ViewRect == ScaledViewRect); ensure(TranslucencyPassResources.DepthTexture == SharedDepthTexture); TranslucencyPassResources.ColorModulateTexture = SharedColorTexture; } else { check(!bIsModulate); } } ++NumProcessedViews; } else if (bRenderTranslucencyHold) { // Main logic: // 1. Copy the holdout background visibility before any translucent pass to the translucent holdout texture. // 2. Run the TranslucencyViewInner logic to accumulate the background visibility (bv) and path throughput (pt) from back to close. // 3. Copy back the alpha channel of the SharedColorTexture. // Notes: // Since alpha will be polluted by alpha holdout blending mode, we cannot directly compose onto the scene color alpha. // with SceneColor.A = SceneColor.A * pt + bv. // E.g., alphaholdout material in front of a translucent material. // Two step direct compose: bv = HoldoutOpacity*(1 - TranslucentOpacity) // This three step copy compose: bv = HoldoutOpacity RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, InViews.Num() > 1, "View%d", ViewIndex); const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); const bool bCompositeBackToSceneColor = true; const bool bLumenGIEnabled = Renderer.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; if (NumProcessedViews == 0 || View.Family->bMultiGPUForkAndJoin) { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); FIntRect CopyRect = TranslucencyPassResources.ViewRect == FIntRect(0,0,0,0) ? View.ViewRect : TranslucencyPassResources.ViewRect; AddCopyBackgroundVisibilityPass(GraphBuilder, View, SceneColorCopyTexture/*SceneTextures.Color.Resolve*/, SeparateTranslucencyColorTexture.Target, CopyRect, FCopyBackgroundVisibilityPS::EVisibilityCopyType::FromSceneColor); } // NOTE: We need to read the depth texture for final fog accumulation, but // in the current phase, we don't need depth texture. const bool bAlphaHoldoutNeedDepthTest = true; FRDGTextureMSAA SeparateTranslucencyDepthTexture; if (bAlphaHoldoutNeedDepthTest) { SeparateTranslucencyDepthTexture = SharedDepthTexture; } // No scale is needed const float ViewportScale = 1.0f; // Simply load as we have already initialized the texture. const ERenderTargetLoadAction SeparateTranslucencyColorLoadAction = ERenderTargetLoadAction::ELoad; FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_SeperateTranslucency); RenderTranslucencyViewInner( GraphBuilder, Renderer, View, ViewIndex, SeparateTranslucencyViewport, ViewportScale, SeparateTranslucencyColorTexture, SeparateTranslucencyColorLoadAction, SeparateTranslucencyDepthTexture.Target, CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData, TranslucencyPass), TranslucencyPass, !bCompositeBackToSceneColor, bRenderInParallel, InstanceCullingManager); { FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); TranslucencyPassResources.ViewRect = View.ViewRect; 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; { ::AddResolveSceneDepthPass(GraphBuilder, View, SeparateTranslucencyDepthTexture); SeparateTranslucencyDepthResolve = SeparateTranslucencyDepthTexture.Resolve; SceneDepthResolve = SceneTextures.Depth.Resolve; } FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass); FTranslucencyComposition TranslucencyComposition; TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::ComposeToSceneColorAlpha; TranslucencyComposition.SceneColor = FScreenPassTextureSlice::CreateFromScreenPassTexture(GraphBuilder, 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(); TranslucencyPassResources.Pass = TranslucencyPass; } ++NumProcessedViews; } else { // When rendering translucent meshes under water, we skip modulate passes which are only required when compositing separate translucency passes from render target. const bool bSkipPass = bViewIsUnderWater && bIsModulate; RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, InViews.Num() > 1 && !bSkipPass, "View%d", ViewIndex); if (bSkipPass) { return; } 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 = Renderer.GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen; FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_RegularTranslucency); RenderTranslucencyViewInner( GraphBuilder, Renderer, View, ViewIndex, Viewport, ViewportScale, SceneTextures.Color, SceneColorLoadAction, SceneTextures.Depth.Target, CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData, TranslucencyPass), TranslucencyPass, bResolveColorTexture, bRenderInParallel, InstanceCullingManager); if (OITData.PassType & OITPass_RegularTranslucency) { OIT::AddOITComposePass(GraphBuilder, View, OITData, SceneTextures.Color.Target); } } } } static bool ShouldRenderTranslucentView(const FViewInfo& View, ETranslucencyView TranslucencyView, ETranslucencyView ViewsToRender) { return View.ShouldRenderView() && EnumHasAnyFlags(TranslucencyView, ViewsToRender); }; void FDeferredShadingSceneRenderer::RenderTranslucency( FDeferredShadingSceneRenderer& Renderer, FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures, const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures, FTranslucencyPassResourcesMap* OutTranslucencyResourceMap, TArray& InViews, ETranslucencyView ViewsToRender, const FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions, FInstanceCullingManager& InstanceCullingManager, bool bStandardTranslucentCanRenderSeparate, FRDGTextureMSAA& OutSharedDepthTexture) { if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater)) { return; } const FSceneViewFamily& ViewFamily = *InViews[0].Family; RDG_EVENT_SCOPE_STAT(GraphBuilder, Translucency, "RenderTranslucency"); RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency); DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution); FRDGTextureRef SceneColorCopyTexture = nullptr; const bool bIsTranslucentHoldoutEnabled = IsPrimitiveAlphaHoldoutEnabledForAnyView(InViews); if (EnumHasAnyFlags(ViewsToRender, ETranslucencyView::AboveWater)) { SceneColorCopyTexture = AddCopySceneColorPass(GraphBuilder, InViews, SceneTextures.Color, /*WithAlpha*/ bIsTranslucentHoldoutEnabled); } // Create a shared depth texture at the correct resolution. 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); OutSharedDepthTexture = CreateTextureMSAA( GraphBuilder, Desc, TEXT("Translucency.DepthMS"), 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 < InViews.Num(); ++ViewIndex) { FViewInfo& View = InViews[ViewIndex]; const ETranslucencyView TranslucencyView = GetTranslucencyView(View); if (!ShouldRenderTranslucentView(View, TranslucencyView, ViewsToRender)) { continue; } const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); AddDownsampleDepthPass( GraphBuilder, View, FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect), FScreenPassRenderTarget(OutSharedDepthTexture.Target, SeparateTranslucencyViewport.Rect, ViewIndex == 0 ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad), EDownsampleDepthFilter::Point); } } else { // Uses the existing depth buffer for depth testing the translucency. OutSharedDepthTexture = SceneTextures.Depth; } if (ViewFamily.AllowTranslucencyAfterDOF()) { RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyStandard, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); if (ViewFamily.AllowStandardTranslucencySeparated() && bStandardTranslucentCanRenderSeparate) { RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyStandardModulate, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); } if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucentBeforeTranslucentAfterDOF) { RenderHairComposition(GraphBuilder, InViews, SceneTextures.Color.Target, SceneTextures.Depth.Target, SceneTextures.Velocity, *OutTranslucencyResourceMap); } RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOF, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterMotionBlur, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); } else // Otherwise render translucent primitives in a single bucket. { RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_AllTranslucency, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); } if (bIsTranslucentHoldoutEnabled && SceneColorCopyTexture) { // Render the translucent holdout background visibility to the alpha channel of SceneColor. RenderTranslucencyInner(Renderer, GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, OutSharedDepthTexture, InViews, ViewsToRender, SeparateTranslucencyDimensions, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyHoldout, InstanceCullingManager, bStandardTranslucentCanRenderSeparate); } } void FDeferredShadingSceneRenderer::UpscaleTranslucencyIfNeeded( FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures, ETranslucencyView ViewsToRender, FTranslucencyPassResourcesMap* OutTranslucencyResourceMap, FRDGTextureMSAA& InSharedDepthTexture) { if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater)) { return; } 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 (!ShouldRenderTranslucentView(View, TranslucencyView, ViewsToRender)) { continue; } // Upscale the responsive AA into original depth buffer. bool bUpscaleResponsiveAA = ( IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod) && InSharedDepthTexture.Target != SceneTextures.Depth.Target); if (bUpscaleResponsiveAA) { const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View); AddUpsampleResponsiveAAPass( GraphBuilder, View, FScreenPassTexture(InSharedDepthTexture.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() && 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(); } } }