void FCompositionLighting::ProcessLpvIndirect(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); if(IsLpvIndirectPassRequired(Context)) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); FRenderingCompositePass* SSAO = Context.Graph.RegisterPass(new FRCPassPostProcessInput(SceneContext.ScreenSpaceAO)); FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new FRCPassPostProcessLpvIndirect()); Pass->SetInput(ePId_Input0, Context.FinalOutput); Pass->SetInput(ePId_Input1, SSAO ); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionLpvIndirect); // we don't replace the final element with the scenecolor because this is what those passes should do by themself CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting")); }
static void AddPostProcessingAmbientCubemap(FPostprocessContext& Context, FRenderingCompositeOutputRef AmbientOcclusion) { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbient()); Pass->SetInput(ePId_Input0, Context.FinalOutput); Pass->SetInput(ePId_Input1, AmbientOcclusion); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); }
// Perform simple upscale and/or editor primitive composite if the fully-featured post process is not in use. void FForwardShadingSceneRenderer::BasicPostProcess(FRHICommandListImmediate& RHICmdList, FViewInfo &View, bool bDoUpscale, bool bDoEditorPrimitives) { FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(RHICmdList, CompositeContext.Graph, View); const bool bBlitRequired = !bDoUpscale && !bDoEditorPrimitives; if (bDoUpscale || bBlitRequired) { // blit from sceneRT to view family target, simple bilinear if upscaling otherwise point filtered. uint32 UpscaleQuality = bDoUpscale ? 1 : 0; FRenderingCompositePass* Node = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessUpscale(UpscaleQuality)); Node->SetInput(ePId_Input0, FRenderingCompositeOutputRef(Context.FinalOutput)); Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.FinalOutput)); Context.FinalOutput = FRenderingCompositeOutputRef(Node); } #if WITH_EDITOR // Composite editor primitives if we had any to draw and compositing is enabled if (bDoEditorPrimitives) { FRenderingCompositePass* EditorCompNode = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessCompositeEditorPrimitives(false)); EditorCompNode->SetInput(ePId_Input0, FRenderingCompositeOutputRef(Context.FinalOutput)); //Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.SceneDepth)); Context.FinalOutput = FRenderingCompositeOutputRef(EditorCompNode); } #endif // currently created on the heap each frame but View.Family->RenderTarget could keep this object and all would be cleaner TRefCountPtr<IPooledRenderTarget> Temp; FSceneRenderTargetItem Item; Item.TargetableTexture = (FTextureRHIRef&)View.Family->RenderTarget->GetRenderTargetTexture(); Item.ShaderResourceTexture = (FTextureRHIRef&)View.Family->RenderTarget->GetRenderTargetTexture(); FPooledRenderTargetDesc Desc; Desc.Extent = View.Family->RenderTarget->GetSizeXY(); // todo: this should come from View.Family->RenderTarget Desc.Format = PF_B8G8R8A8; Desc.NumMips = 1; GRenderTargetPool.CreateUntrackedElement(Desc, Temp, Item); Context.FinalOutput.GetOutput()->PooledRenderTarget = Temp; Context.FinalOutput.GetOutput()->RenderTargetDesc = Desc; CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("ES2BasicPostProcess")); }
void FCompositionLighting::ProcessBeforeBasePass(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); // so that the passes can register themselves to the graph { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); // Add the passes we want to add to the graph (commenting a line means the pass is not inserted into the graph) ---------- // decals are before AmbientOcclusion so the decal can output a normal that AO is affected by if (Context.View.Family->EngineShowFlags.Decals && !Context.View.Family->EngineShowFlags.ShaderComplexity && IsDBufferEnabled()) { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessDeferredDecals(DRS_BeforeBasePass)); Pass->SetInput(ePId_Input0, Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionBeforeBasePass); CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("Composition_BeforeBasePass")); } }
static void AddDeferredDecalsBeforeLighting(FPostprocessContext& Context) { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessDeferredDecals(1)); Pass->SetInput(ePId_Input0, Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); }
// Perform simple upscale and/or editor primitive composite if the fully-featured post process is not in use. void FForwardShadingSceneRenderer::BasicPostProcess(FRHICommandListImmediate& RHICmdList, FViewInfo &View, bool bDoUpscale, bool bDoEditorPrimitives) { FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); if (bDoUpscale) { // simple bilinear upscaling for ES2. FRenderingCompositePass* Node = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessUpscale(1, 0.0f)); Node->SetInput(ePId_Input0, FRenderingCompositeOutputRef(Context.FinalOutput)); Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.FinalOutput)); Context.FinalOutput = FRenderingCompositeOutputRef(Node); } // Composite editor primitives if we had any to draw and compositing is enabled if (bDoEditorPrimitives) { FRenderingCompositePass* EditorCompNode = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessCompositeEditorPrimitives(false)); EditorCompNode->SetInput(ePId_Input0, FRenderingCompositeOutputRef(Context.FinalOutput)); //Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.SceneDepth)); Context.FinalOutput = FRenderingCompositeOutputRef(EditorCompNode); } // currently created on the heap each frame but View.Family->RenderTarget could keep this object and all would be cleaner TRefCountPtr<IPooledRenderTarget> Temp; FSceneRenderTargetItem Item; Item.TargetableTexture = (FTextureRHIRef&)View.Family->RenderTarget->GetRenderTargetTexture(); Item.ShaderResourceTexture = (FTextureRHIRef&)View.Family->RenderTarget->GetRenderTargetTexture(); FPooledRenderTargetDesc Desc; Desc.Extent = View.Family->RenderTarget->GetSizeXY(); // todo: this should come from View.Family->RenderTarget Desc.Format = PF_B8G8R8A8; Desc.NumMips = 1; GRenderTargetPool.CreateUntrackedElement(Desc, Temp, Item); Context.FinalOutput.GetOutput()->PooledRenderTarget = Temp; Context.FinalOutput.GetOutput()->RenderTargetDesc = Desc; CompositeContext.Root->AddDependency(Context.FinalOutput); CompositeContext.Process(TEXT("ES2BasicPostProcess")); }
/** Applies Temporal AA to the light shaft source. */ void ApplyTemporalAA( FRHICommandListImmediate& RHICmdList, FViewInfo& View, const TCHAR* HistoryRTName, /** Contains last frame's history, if non-NULL. This will be updated with the new frame's history. */ TRefCountPtr<IPooledRenderTarget>* HistoryState, /** Source mask (for either occlusion or bloom). */ TRefCountPtr<IPooledRenderTarget>& LightShaftsSource, /** Output of Temporal AA for the next step in the pipeline. */ TRefCountPtr<IPooledRenderTarget>& HistoryOutput) { if (View.FinalPostProcessSettings.AntiAliasingMethod == AAM_TemporalAA && HistoryState) { if (*HistoryState && !View.bCameraCut) { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); // Nodes for input render targets FRenderingCompositePass* LightShaftSetup = Context.Graph.RegisterPass( new(FMemStack::Get()) FRCPassPostProcessInput( LightShaftsSource ) ); FRenderingCompositePass* HistoryInput = Context.Graph.RegisterPass( new(FMemStack::Get()) FRCPassPostProcessInput( *HistoryState ) ); // Temporal AA node FRenderingCompositePass* NodeTemporalAA = Context.Graph.RegisterPass( new(FMemStack::Get()) FRCPassPostProcessLightShaftTemporalAA ); // Setup inputs on Temporal AA node as the shader expects NodeTemporalAA->SetInput( ePId_Input0, LightShaftSetup ); NodeTemporalAA->SetInput( ePId_Input1, FRenderingCompositeOutputRef( HistoryInput ) ); NodeTemporalAA->SetInput( ePId_Input2, FRenderingCompositeOutputRef( HistoryInput ) ); // Reuse a render target from the pool with a consistent name, for vis purposes TRefCountPtr<IPooledRenderTarget> NewHistory; AllocateOrReuseLightShaftRenderTarget(RHICmdList, NewHistory, HistoryRTName); // Setup the output to write to the new history render target Context.FinalOutput = FRenderingCompositeOutputRef(NodeTemporalAA); Context.FinalOutput.GetOutput()->RenderTargetDesc = NewHistory->GetDesc(); Context.FinalOutput.GetOutput()->PooledRenderTarget = NewHistory; // Execute Temporal AA CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("LightShaftTemporalAA")); // Update the view state's render target reference with the new history *HistoryState = NewHistory; HistoryOutput = NewHistory; } else { // Use the current frame's mask for next frame's history, without invoking the Temporal AA shader *HistoryState = LightShaftsSource; HistoryOutput = LightShaftsSource; LightShaftsSource = NULL; AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShaftsSource, HistoryRTName); } } else { // Temporal AA is disabled or there is no view state - pass through HistoryOutput = LightShaftsSource; } }
void FCompositionLighting::ProcessAfterLighting(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDiffuse); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapNormal); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDepth); { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); FRenderingCompositeOutputRef AmbientOcclusion; // Screen Space Subsurface Scattering { float Radius = CVarSSSScale.GetValueOnRenderThread(); bool bSimpleDynamicLighting = IsSimpleDynamicLightingEnabled(); bool bScreenSpaceSubsurfacePassNeeded = (View.ShadingModelMaskInView & (1 << MSM_SubsurfaceProfile)) != 0; if (bScreenSpaceSubsurfacePassNeeded && Radius > 0 && !bSimpleDynamicLighting && View.Family->EngineShowFlags.SubsurfaceScattering && //@todo-rco: Remove this when we fix the cross-compiler !IsOpenGLPlatform(View.GetShaderPlatform())) { // can be optimized out if we don't do split screen/stereo rendering (should be done after we some post process refactoring) FRenderingCompositePass* PassExtractSpecular = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceExtractSpecular()); PassExtractSpecular->SetInput(ePId_Input0, Context.FinalOutput); FRenderingCompositePass* PassSetup = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceSetup(View)); PassSetup->SetInput(ePId_Input0, Context.FinalOutput); FRenderingCompositePass* Pass0 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(0)); Pass0->SetInput(ePId_Input0, PassSetup); FRenderingCompositePass* Pass1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(1)); Pass1->SetInput(ePId_Input0, Pass0); Pass1->SetInput(ePId_Input1, PassSetup); // full res composite pass, no blurring (Radius=0) FRenderingCompositePass* RecombinePass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceRecombine()); RecombinePass->SetInput(ePId_Input0, Pass1); RecombinePass->SetInput(ePId_Input1, PassExtractSpecular); SCOPED_DRAW_EVENT(RHICmdList, CompositionLighting_SSSSS); CompositeContext.Process(RecombinePass, TEXT("CompositionLighting_SSSSS")); } } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionAfterLighting); // we don't replace the final element with the scenecolor because this is what those passes should do by themself CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting")); } // We only release the after the last view was processed (SplitScreen) if(View.Family->Views[View.Family->Views.Num() - 1] == &View) { // The RT should be released as early as possible to allow sharing of that memory for other purposes. // This becomes even more important with some limited VRam (XBoxOne). SceneContext.SetLightAttenuation(0); } }
void FCompositionLighting::ProcessAfterBasePass(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); // might get renamed to refracted or ...WithAO SceneContext.GetSceneColor()->SetDebugName(TEXT("SceneColor")); // to be able to observe results with VisualizeTexture GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GetSceneColor()); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferA); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferB); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferC); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferD); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferE); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GBufferVelocity); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ScreenSpaceAO); // so that the passes can register themselves to the graph { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); // Add the passes we want to add to the graph ---------- if(Context.View.Family->EngineShowFlags.Decals && !Context.View.Family->EngineShowFlags.ShaderComplexity) { // DRS_AfterBasePass is for Volumetric decals which don't support ShaderComplexity yet FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessDeferredDecals(DRS_AfterBasePass)); Pass->SetInput(ePId_Input0, Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } // decals are before AmbientOcclusion so the decal can output a normal that AO is affected by if( Context.View.Family->EngineShowFlags.Decals && !Context.View.Family->EngineShowFlags.VisualizeLightCulling) // decal are distracting when looking at LightCulling { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessDeferredDecals(DRS_BeforeLighting)); Pass->SetInput(ePId_Input0, Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } FRenderingCompositeOutputRef AmbientOcclusion; if(uint32 Levels = ComputeAmbientOcclusionPassCount(Context)) { AmbientOcclusion = AddPostProcessingAmbientOcclusion(RHICmdList, Context, Levels); } if(IsAmbientCubemapPassRequired(Context)) { AddPostProcessingAmbientCubemap(Context, AmbientOcclusion); } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, LightCompositionTasks_PreLighting); TRefCountPtr<IPooledRenderTarget>& SceneColor = SceneContext.GetSceneColor(); Context.FinalOutput.GetOutput()->RenderTargetDesc = SceneColor->GetDesc(); Context.FinalOutput.GetOutput()->PooledRenderTarget = SceneColor; CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting_AfterBasePass")); } }
void ScreenSpaceReflections(FRHICommandListImmediate& RHICmdList, FViewInfo& View, TRefCountPtr<IPooledRenderTarget>& SSROutput) { BuildHZB(RHICmdList, View); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context( CompositeContext.Graph, View ); FSceneViewState* ViewState = (FSceneViewState*)Context.View.State; FRenderingCompositePass* SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( GSceneRenderTargets.GetSceneColor() ) ); FRenderingCompositePass* HZBInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->HZB.Texture ) ); bool bPrevFrame = 0; if( ViewState && ViewState->TemporalAAHistoryRT && !Context.View.bCameraCut ) { SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->TemporalAAHistoryRT ) ); bPrevFrame = 1; } { FRenderingCompositePass* TracePass = Context.Graph.RegisterPass( new FRCPassPostProcessScreenSpaceReflections( bPrevFrame ) ); TracePass->SetInput( ePId_Input0, SceneColorInput ); TracePass->SetInput( ePId_Input1, HZBInput ); Context.FinalOutput = FRenderingCompositeOutputRef( TracePass ); } const bool bTemporalFilter = View.FinalPostProcessSettings.AntiAliasingMethod != AAM_TemporalAA || CVarSSRTemporal.GetValueOnRenderThread() != 0; if( ViewState && bTemporalFilter ) { { FRenderingCompositeOutputRef HistoryInput; if( ViewState && ViewState->SSRHistoryRT && !Context.View.bCameraCut ) { HistoryInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->SSRHistoryRT ) ); } else { // No history, use black HistoryInput = Context.Graph.RegisterPass(new FRCPassPostProcessInput(GSystemTextures.BlackDummy)); } FRenderingCompositePass* TemporalAAPass = Context.Graph.RegisterPass( new FRCPassPostProcessSSRTemporalAA ); TemporalAAPass->SetInput( ePId_Input0, Context.FinalOutput ); TemporalAAPass->SetInput( ePId_Input1, HistoryInput ); //TemporalAAPass->SetInput( ePId_Input2, VelocityInput ); Context.FinalOutput = FRenderingCompositeOutputRef( TemporalAAPass ); } if( ViewState ) { FRenderingCompositePass* HistoryOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &ViewState->SSRHistoryRT ) ); HistoryOutput->SetInput( ePId_Input0, Context.FinalOutput ); Context.FinalOutput = FRenderingCompositeOutputRef( HistoryOutput ); } } { FRenderingCompositePass* ReflectionOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &SSROutput ) ); ReflectionOutput->SetInput( ePId_Input0, Context.FinalOutput ); Context.FinalOutput = FRenderingCompositeOutputRef( ReflectionOutput ); } CompositeContext.Root->AddDependency( Context.FinalOutput ); CompositeContext.Process(TEXT("ReflectionEnvironments")); }
void FCompositionLighting::ProcessAfterLighting(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(RHICmdList, CompositeContext.Graph, View); FRenderingCompositeOutputRef AmbientOcclusion; // Screen Space Subsurface Scattering { float Radius = CVarSSSScale.GetValueOnRenderThread(); bool bSimpleDynamicLighting = IsAnyForwardShadingEnabled(View.GetShaderPlatform()); bool bScreenSpaceSubsurfacePassNeeded = ((View.ShadingModelMaskInView & (1 << MSM_SubsurfaceProfile)) != 0) && IsSubsurfacePostprocessRequired(); bool bSubsurfaceAllowed = CVarSubsurfaceScattering.GetValueOnRenderThread() == 1; if (bScreenSpaceSubsurfacePassNeeded && !bSimpleDynamicLighting && bSubsurfaceAllowed) { bool bHalfRes = CVarSSSHalfRes.GetValueOnRenderThread() != 0; bool bSingleViewportMode = View.Family->Views.Num() == 1; if(Radius > 0 && View.Family->EngineShowFlags.SubsurfaceScattering) { FRenderingCompositePass* PassSetup = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceSetup(View, bHalfRes)); PassSetup->SetInput(ePId_Input0, Context.FinalOutput); FRenderingCompositePass* PassX = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(0, bHalfRes)); PassX->SetInput(ePId_Input0, PassSetup); FRenderingCompositePass* PassY = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(1, bHalfRes)); PassY->SetInput(ePId_Input0, PassX); PassY->SetInput(ePId_Input1, PassSetup); // full res composite pass, no blurring (Radius=0), replaces SceneColor FRenderingCompositePass* RecombinePass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceRecombine(bHalfRes, bSingleViewportMode)); RecombinePass->SetInput(ePId_Input0, Context.FinalOutput); RecombinePass->SetInput(ePId_Input1, PassY); RecombinePass->SetInput(ePId_Input2, PassSetup); Context.FinalOutput = FRenderingCompositeOutputRef(RecombinePass); } else { // needed for Scalability FRenderingCompositePass* RecombinePass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceRecombine(bHalfRes, bSingleViewportMode)); RecombinePass->SetInput(ePId_Input0, Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(RecombinePass); } } } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionAfterLighting); SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionPostLighting); // we don't replace the final element with the scenecolor because this is what those passes should do by themself CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting")); } // We only release the after the last view was processed (SplitScreen) if(View.Family->Views[View.Family->Views.Num() - 1] == &View) { // The RT should be released as early as possible to allow sharing of that memory for other purposes. // This becomes even more important with some limited VRam (XBoxOne). SceneContext.SetLightAttenuation(0); } }