// @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 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(RHICmdList, 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; uint32 SSAOLevels = ComputeAmbientOcclusionPassCount(Context.View); if (SSAOLevels) { if(!FSSAOHelper::IsAmbientOcclusionAsyncCompute(Context.View, SSAOLevels)) { AmbientOcclusion = AddPostProcessingAmbientOcclusion(RHICmdList, Context, SSAOLevels); } if (FSSAOHelper::IsBasePassAmbientOcclusionRequired(Context.View)) { FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessBasePassAO()); Pass->AddDependency(Context.FinalOutput); Context.FinalOutput = FRenderingCompositeOutputRef(Pass); } } if (IsAmbientCubemapPassRequired(Context.View)) { AddPostProcessingAmbientCubemap(Context, AmbientOcclusion); } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, LightCompositionTasks_PreLighting); SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CompositionPreLighting); TRefCountPtr<IPooledRenderTarget>& SceneColor = SceneContext.GetSceneColor(); Context.FinalOutput.GetOutput()->RenderTargetDesc = SceneColor->GetDesc(); Context.FinalOutput.GetOutput()->PooledRenderTarget = SceneColor; CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting_AfterBasePass")); } }