// 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::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")); }
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")); } }
void FCompositionLighting::ProcessAsyncSSAO(FRHICommandListImmediate& RHICmdList, TArray<FViewInfo>& Views) { check(IsInRenderingThread()); PrepareAsyncSSAO(RHICmdList, Views); // so that the passes can register themselves to the graph for (int32 i = 0; i < Views.Num(); ++i) { FViewInfo& View = Views[i]; FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); // Add the passes we want to add to the graph (commenting a line means the pass is not inserted into the graph) ---------- uint32 Levels = ComputeAmbientOcclusionPassCount(View); if (FSSAOHelper::IsAmbientOcclusionAsyncCompute(View, Levels)) { FPostprocessContext Context(RHICmdList, CompositeContext.Graph, View); FRenderingCompositeOutputRef AmbientOcclusion = AddPostProcessingAmbientOcclusion(RHICmdList, Context, Levels); Context.FinalOutput = FRenderingCompositeOutputRef(AmbientOcclusion); // The graph setup should be finished before this line ---------------------------------------- CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("Composition_ProcessAsyncSSAO")); } } FinishAsyncSSAO(RHICmdList); }
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); }
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(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::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")); } }
// @param Levels 0..4, how many different resolution levels we want to render static FRenderingCompositeOutputRef AddPostProcessingAmbientOcclusion(FRHICommandListImmediate& RHICmdList, FPostprocessContext& Context, uint32 Levels) { check(Levels >= 0 && Levels <= 4); FRenderingCompositePass* AmbientOcclusionInMip1 = 0; FRenderingCompositePass* AmbientOcclusionInMip2 = 0; FRenderingCompositePass* AmbientOcclusionInMip3 = 0; FRenderingCompositePass* AmbientOcclusionPassMip1 = 0; FRenderingCompositePass* AmbientOcclusionPassMip2 = 0; FRenderingCompositePass* AmbientOcclusionPassMip3 = 0; // generate input in half, quarter, .. resolution AmbientOcclusionInMip1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusionSetup()); AmbientOcclusionInMip1->SetInput(ePId_Input0, Context.SceneDepth); if(Levels >= 3) { AmbientOcclusionInMip2 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusionSetup()); AmbientOcclusionInMip2->SetInput(ePId_Input1, FRenderingCompositeOutputRef(AmbientOcclusionInMip1, ePId_Output0)); } if(Levels >= 4) { AmbientOcclusionInMip3 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusionSetup()); AmbientOcclusionInMip3->SetInput(ePId_Input1, FRenderingCompositeOutputRef(AmbientOcclusionInMip2, ePId_Output0)); } FRenderingCompositePass* HZBInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( const_cast< FViewInfo& >( Context.View ).HZB ) ); // upsample from lower resolution if(Levels >= 4) { AmbientOcclusionPassMip3 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion()); AmbientOcclusionPassMip3->SetInput(ePId_Input0, AmbientOcclusionInMip3); AmbientOcclusionPassMip3->SetInput(ePId_Input1, AmbientOcclusionInMip3); AmbientOcclusionPassMip3->SetInput(ePId_Input3, HZBInput); } if(Levels >= 3) { AmbientOcclusionPassMip2 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion()); AmbientOcclusionPassMip2->SetInput(ePId_Input0, AmbientOcclusionInMip2); AmbientOcclusionPassMip2->SetInput(ePId_Input1, AmbientOcclusionInMip2); AmbientOcclusionPassMip2->SetInput(ePId_Input2, AmbientOcclusionPassMip3); AmbientOcclusionPassMip2->SetInput(ePId_Input3, HZBInput); } if(Levels >= 2) { AmbientOcclusionPassMip1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion()); AmbientOcclusionPassMip1->SetInput(ePId_Input0, AmbientOcclusionInMip1); AmbientOcclusionPassMip1->SetInput(ePId_Input1, AmbientOcclusionInMip1); AmbientOcclusionPassMip1->SetInput(ePId_Input2, AmbientOcclusionPassMip2); AmbientOcclusionPassMip1->SetInput(ePId_Input3, HZBInput); } FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); FRenderingCompositePass* GBufferA = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessInput(SceneContext.GBufferA)); // finally full resolution FRenderingCompositePass* AmbientOcclusionPassMip0 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion(false)); AmbientOcclusionPassMip0->SetInput(ePId_Input0, GBufferA); AmbientOcclusionPassMip0->SetInput(ePId_Input1, AmbientOcclusionInMip1); AmbientOcclusionPassMip0->SetInput(ePId_Input2, AmbientOcclusionPassMip1); AmbientOcclusionPassMip0->SetInput(ePId_Input3, HZBInput); // to make sure this pass is processed as well (before), needed to make process decals before computing AO AmbientOcclusionInMip1->AddDependency(Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(AmbientOcclusionPassMip0); SceneContext.bScreenSpaceAOIsValid = true; if(IsBasePassAmbientOcclusionRequired(Context)) { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessBasePassAO()); Pass->AddDependency(Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } return FRenderingCompositeOutputRef(AmbientOcclusionPassMip0); }
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")); }
/** * Renders the view family. */ void FForwardShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { if(!ViewFamily.EngineShowFlags.Rendering) { return; } auto FeatureLevel = ViewFamily.GetFeatureLevel(); // Initialize global system textures (pass-through if already initialized). GSystemTextures.InitializeTextures(RHICmdList, FeatureLevel); // Allocate the maximum scene render target space for the current view family. GSceneRenderTargets.Allocate(ViewFamily); // Find the visible primitives. InitViews(RHICmdList); RenderShadowDepthMaps(RHICmdList); // Notify the FX system that the scene is about to be rendered. if (Scene->FXSystem) { Scene->FXSystem->PreRender(RHICmdList); } GRenderTargetPool.VisualizeTexture.OnStartFrame(Views[0]); // Dynamic vertex and index buffers need to be committed before rendering. FGlobalDynamicVertexBuffer::Get().Commit(); FGlobalDynamicIndexBuffer::Get().Commit(); // This might eventually be a problem with multiple views. // Using only view 0 to check to do on-chip transform of alpha. FViewInfo& View = Views[0]; const bool bGammaSpace = !IsMobileHDR(); const bool bRequiresUpscale = ((uint32)ViewFamily.RenderTarget->GetSizeXY().X > ViewFamily.FamilySizeX || (uint32)ViewFamily.RenderTarget->GetSizeXY().Y > ViewFamily.FamilySizeY); const bool bRenderToScene = bRequiresUpscale || FSceneRenderer::ShouldCompositeEditorPrimitives(View); if (bGammaSpace && !bRenderToScene) { SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), GSceneRenderTargets.GetSceneDepthTexture(), ESimpleRenderTargetMode::EClearToDefault); } else { // Begin rendering to scene color GSceneRenderTargets.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EClearToDefault); } if (GIsEditor) { RHICmdList.Clear(true, Views[0].BackgroundColor, false, 0, false, 0, FIntRect()); } RenderForwardShadingBasePass(RHICmdList); // Make a copy of the scene depth if the current hardware doesn't support reading and writing to the same depth buffer GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture(RHICmdList); // Notify the FX system that opaque primitives have been rendered. if (Scene->FXSystem) { Scene->FXSystem->PostRenderOpaque(RHICmdList); } // Draw translucency. if (ViewFamily.EngineShowFlags.Translucency) { SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); // Note: Forward pass has no SeparateTranslucency, so refraction effect order with Transluency is different. // Having the distortion applied between two different translucency passes would make it consistent with the deferred pass. // This is not done yet. if (ViewFamily.EngineShowFlags.Refraction) { // to apply refraction effect by distorting the scene color RenderDistortion(RHICmdList); } RenderTranslucency(RHICmdList); } static const auto CVarMobileMSAA = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA")); bool bOnChipSunMask = GSupportsRenderTargetFormat_PF_FloatRGBA && GSupportsShaderFramebufferFetch && ViewFamily.EngineShowFlags.PostProcessing && ((View.bLightShaftUse) || (View.FinalPostProcessSettings.DepthOfFieldScale > 0.0) || ((ViewFamily.GetShaderPlatform() == SP_METAL) && (CVarMobileMSAA ? CVarMobileMSAA->GetValueOnAnyThread() > 1 : false)) ); if (!bGammaSpace && bOnChipSunMask) { // Convert alpha from depth to circle of confusion with sunshaft intensity. // This is done before resolve on hardware with framebuffer fetch. // This will break when PrePostSourceViewportSize is not full size. FIntPoint PrePostSourceViewportSize = GSceneRenderTargets.GetBufferSizeXY(); FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FRenderingCompositePass* PostProcessSunMask = CompositeContext.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSunMaskES2(PrePostSourceViewportSize, true)); CompositeContext.Root->AddDependency(FRenderingCompositeOutputRef(PostProcessSunMask)); CompositeContext.Process(TEXT("OnChipAlphaTransform")); } if (!bGammaSpace || bRenderToScene) { // Resolve the scene color for post processing. GSceneRenderTargets.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); // Drop depth and stencil before post processing to avoid export. RHICmdList.DiscardRenderTargets(true, true, 0); } if (!bGammaSpace) { // Finish rendering for each view, or the full stereo buffer if enabled if (ViewFamily.bResolveScene) { if (ViewFamily.EngineShowFlags.StereoRendering) { check(Views.Num() > 1); //@todo ES2 stereo post: until we get proper stereo postprocessing for ES2, process the stereo buffer as one view FIntPoint OriginalMax0 = Views[0].ViewRect.Max; Views[0].ViewRect.Max = Views[1].ViewRect.Max; GPostProcessing.ProcessES2(RHICmdList, Views[0], bOnChipSunMask); Views[0].ViewRect.Max = OriginalMax0; } else { SCOPED_DRAW_EVENT(RHICmdList, PostProcessing); SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime); for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); GPostProcessing.ProcessES2(RHICmdList, Views[ViewIndex], bOnChipSunMask); } } } } else if (bRenderToScene) { BasicPostProcess(RHICmdList, View, bRequiresUpscale, FSceneRenderer::ShouldCompositeEditorPrimitives(View)); } RenderFinish(RHICmdList); }
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); } }
// @param Levels 0..3, how many different resolution levels we want to render static FRenderingCompositeOutputRef AddPostProcessingAmbientOcclusion(FRHICommandListImmediate& RHICmdList, FPostprocessContext& Context, uint32 Levels) { check(Levels >= 0 && Levels <= 3); FRenderingCompositePass* AmbientOcclusionInMip1 = 0; FRenderingCompositePass* AmbientOcclusionInMip2 = 0; FRenderingCompositePass* AmbientOcclusionPassMip1 = 0; FRenderingCompositePass* AmbientOcclusionPassMip2 = 0; FRenderingCompositePass* HZBInput = Context.Graph.RegisterPass(new FRCPassPostProcessInput(const_cast<FViewInfo&>(Context.View).HZB)); { // generate input in half, quarter, .. resolution ESSAOType DownResAOType = FSSAOHelper::IsAmbientOcclusionCompute(Context.View) ? ESSAOType::ECS : ESSAOType::EPS; if (Levels >= 2) { AmbientOcclusionInMip1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusionSetup()); AmbientOcclusionInMip1->SetInput(ePId_Input0, Context.SceneDepth); } if (Levels >= 3) { AmbientOcclusionInMip2 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusionSetup()); AmbientOcclusionInMip2->SetInput(ePId_Input1, FRenderingCompositeOutputRef(AmbientOcclusionInMip1, ePId_Output0)); } // upsample from lower resolution if (Levels >= 3) { AmbientOcclusionPassMip2 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion(Context.View, DownResAOType)); AmbientOcclusionPassMip2->SetInput(ePId_Input0, AmbientOcclusionInMip2); AmbientOcclusionPassMip2->SetInput(ePId_Input1, AmbientOcclusionInMip2); AmbientOcclusionPassMip2->SetInput(ePId_Input3, HZBInput); } if (Levels >= 2) { AmbientOcclusionPassMip1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion(Context.View, DownResAOType)); AmbientOcclusionPassMip1->SetInput(ePId_Input0, AmbientOcclusionInMip1); AmbientOcclusionPassMip1->SetInput(ePId_Input1, AmbientOcclusionInMip1); AmbientOcclusionPassMip1->SetInput(ePId_Input2, AmbientOcclusionPassMip2); AmbientOcclusionPassMip1->SetInput(ePId_Input3, HZBInput); } } FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); FRenderingCompositePass* GBufferA = nullptr; // finally full resolution ESSAOType FullResAOType = ESSAOType::EPS; { if(FSSAOHelper::IsAmbientOcclusionCompute(Context.View)) { if(FSSAOHelper::IsAmbientOcclusionAsyncCompute(Context.View, Levels)) { FullResAOType = ESSAOType::EAsyncCS; } else { FullResAOType = ESSAOType::ECS; } } } if (FullResAOType != ESSAOType::EAsyncCS) { GBufferA = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessInput(SceneContext.GBufferA)); } FRenderingCompositePass* AmbientOcclusionPassMip0 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessAmbientOcclusion(Context.View, FullResAOType, false)); AmbientOcclusionPassMip0->SetInput(ePId_Input0, GBufferA); AmbientOcclusionPassMip0->SetInput(ePId_Input1, AmbientOcclusionInMip1); AmbientOcclusionPassMip0->SetInput(ePId_Input2, AmbientOcclusionPassMip1); AmbientOcclusionPassMip0->SetInput(ePId_Input3, HZBInput); // to make sure this pass is processed as well (before), needed to make process decals before computing AO if(AmbientOcclusionInMip1) { AmbientOcclusionInMip1->AddDependency(Context.FinalOutput); } else { AmbientOcclusionPassMip0->AddDependency(Context.FinalOutput); } Context.FinalOutput = FRenderingCompositeOutputRef(AmbientOcclusionPassMip0); SceneContext.bScreenSpaceAOIsValid = true; return FRenderingCompositeOutputRef(AmbientOcclusionPassMip0); }