diff --git a/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/BasePass C++.md b/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/BasePass C++.md index cf20a20..c1bdc95 100644 --- a/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/BasePass C++.md +++ b/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/BasePass C++.md @@ -22,7 +22,7 @@ FDeferredShadingSceneRenderer::RenderBasePassInternal() => FBasePassMeshProcessor::TryAddMeshBatch => ## 大致流程 -1. 绑定GBuffer与Depth。 +1. 创建MRT并绑定、取得深度缓存。 ```c++ const FExclusiveDepthStencil ExclusiveDepthStencil(BasePassDepthStencilAccess); @@ -58,10 +58,173 @@ GraphBuilder.AddPass(RDG_EVENT_NAME("GBufferClear"), PassParameters, ERDGPassFla } }); ``` -3. +3. RenderTargetBindingSlots +```c++ +// Render targets bindings should remain constant at this point. +FRenderTargetBindingSlots BasePassRenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::ELoad, BasePassTexturesView); +BasePassRenderTargets.DepthStencil = FDepthStencilBinding(BasePassDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, ExclusiveDepthStencil); +``` +4. RenderBasePassInternal() +5. RenderAnisotropyPass() +# MeshDraw +## RenderBasePassInternal() +RenderNaniteBasePass()为一个Lambda,最终调用**Nanite::DrawBasePass()** 渲染Nanite物体的BasePass。其他相关渲染代码如下: +```c++ +SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime); + RDG_EVENT_SCOPE(GraphBuilder, "BasePass"); + RDG_GPU_STAT_SCOPE(GraphBuilder, Basepass); -# SetDepthStencilStateForBasePass() + const bool bDrawSceneViewsInOneNanitePass = Views.Num() > 1 && Nanite::ShouldDrawSceneViewsInOneNanitePass(Views[0]); + if (bParallelBasePass)//并行渲染模式 + { + RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsBasePassWaitForTasksEnabled()); + + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) + { + FViewInfo& View = Views[ViewIndex]; + RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); + RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); + View.BeginRenderView(); + + const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen; + + FMeshPassProcessorRenderState DrawRenderState; + SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState); + + FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters(); + PassParameters->View = View.GetShaderParameters(); + PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer; + PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled); + PassParameters->RenderTargets = BasePassRenderTargets; + PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::BasePass); + + const bool bShouldRenderView = View.ShouldRenderView(); + if (bShouldRenderView) + { + View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("BasePassParallel"), + PassParameters, + ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass, + [this, &View, PassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList) + { + FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), View, FParallelCommandListBindings(PassParameters)); + View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &PassParameters->InstanceCullingDrawParams); + }); + } + + const bool bShouldRenderViewForNanite = bNaniteEnabled && (!bDrawSceneViewsInOneNanitePass || ViewIndex == 0); // when bDrawSceneViewsInOneNanitePass, the first view should cover all the other atlased ones + if (bShouldRenderViewForNanite) + { + // Should always have a full Z prepass with Nanite + check(ShouldRenderPrePass()); + //渲染Nanite物体BasePass + RenderNaniteBasePass(View, ViewIndex); + } + + //渲染编辑器相关的图元物体 + RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager); + + //渲染大气 + if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere) + { + FOpaqueBasePassParameters* SkyPassPassParameters = GraphBuilder.AllocParameters(); + SkyPassPassParameters->BasePass = PassParameters->BasePass; + SkyPassPassParameters->RenderTargets = BasePassRenderTargets; + SkyPassPassParameters->View = View.GetShaderParameters(); + SkyPassPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer; + + View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassPassParameters->InstanceCullingDrawParams); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("SkyPassParallel"), + SkyPassPassParameters, + ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass, + [this, &View, SkyPassPassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList) + { + FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), View, FParallelCommandListBindings(SkyPassPassParameters)); + View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &SkyPassPassParameters->InstanceCullingDrawParams); + }); + } + } + } + else + { + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) + { + FViewInfo& View = Views[ViewIndex]; + RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask); + RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); + View.BeginRenderView(); + + const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen; + + FMeshPassProcessorRenderState DrawRenderState; + SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState); + + FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters(); + PassParameters->View = View.GetShaderParameters(); + PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer; + PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled); + PassParameters->RenderTargets = BasePassRenderTargets; + PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::BasePass); + + const bool bShouldRenderView = View.ShouldRenderView(); + if (bShouldRenderView) + { + View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("BasePass"), + PassParameters, + ERDGPassFlags::Raster, + [this, &View, PassParameters](FRHICommandList& RHICmdList) + { + SetStereoViewport(RHICmdList, View, 1.0f); + View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(nullptr, RHICmdList, &PassParameters->InstanceCullingDrawParams); + } + ); + } + + const bool bShouldRenderViewForNanite = bNaniteEnabled && (!bDrawSceneViewsInOneNanitePass || ViewIndex == 0); // when bDrawSceneViewsInOneNanitePass, the first view should cover all the other atlased ones + if (bShouldRenderViewForNanite) + { + // Should always have a full Z prepass with Nanite + check(ShouldRenderPrePass()); + + RenderNaniteBasePass(View, ViewIndex); + } + + RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager); + + if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere) + { + FOpaqueBasePassParameters* SkyPassParameters = GraphBuilder.AllocParameters(); + SkyPassParameters->BasePass = PassParameters->BasePass; + SkyPassParameters->RenderTargets = BasePassRenderTargets; + SkyPassParameters->View = View.GetShaderParameters(); + SkyPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer; + + View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassParameters->InstanceCullingDrawParams); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("SkyPass"), + SkyPassParameters, + ERDGPassFlags::Raster, + [this, &View, SkyPassParameters](FRHICommandList& RHICmdList) + { + SetStereoViewport(RHICmdList, View, 1.0f); + View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(nullptr, RHICmdList, &SkyPassParameters->InstanceCullingDrawParams); + } + ); + } + } + } +``` + +### SetDepthStencilStateForBasePass() ```c++ void SetDepthStencilStateForBasePass( FMeshPassProcessorRenderState& DrawRenderState, @@ -98,4 +261,118 @@ void SetDepthStencilStateForBasePass( } } ``` -# \ No newline at end of file +## AnisotropyPass +Anisotropy的RT设置: +- RenderTarget:SceneTextures.GBufferF。 +- DepthStencil:SceneTextures.Depth.Target。**ERenderTargetLoadAction::ELoad**、**FExclusiveDepthStencil::DepthRead_StencilNop** + +### 管线状态 +在FAnisotropyMeshProcessor::CollectPSOInitializers()中: +```c++ +ETextureCreateFlags GBufferFCreateFlags; +EPixelFormat GBufferFPixelFormat = FSceneTextures::GetGBufferFFormatAndCreateFlags(GBufferFCreateFlags); +AddRenderTargetInfo(GBufferFPixelFormat, GBufferFCreateFlags, RenderTargetsInfo); +SetupDepthStencilInfo(PF_DepthStencil, SceneTexturesConfig.DepthCreateFlags, ERenderTargetLoadAction::ELoad, + ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilNop, RenderTargetsInfo); +``` + +```c++ +void SetupDepthStencilInfo( + EPixelFormat DepthStencilFormat, + ETextureCreateFlags DepthStencilCreateFlags, + ERenderTargetLoadAction DepthTargetLoadAction, + ERenderTargetLoadAction StencilTargetLoadAction, + FExclusiveDepthStencil DepthStencilAccess, + FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo) +{ + // Setup depth stencil state + RenderTargetsInfo.DepthStencilTargetFormat = DepthStencilFormat; + RenderTargetsInfo.DepthStencilTargetFlag = DepthStencilCreateFlags; + + RenderTargetsInfo.DepthTargetLoadAction = DepthTargetLoadAction; + RenderTargetsInfo.StencilTargetLoadAction = StencilTargetLoadAction; + RenderTargetsInfo.DepthStencilAccess = DepthStencilAccess; + + const ERenderTargetStoreAction StoreAction = EnumHasAnyFlags(RenderTargetsInfo.DepthStencilTargetFlag, TexCreate_Memoryless) ? ERenderTargetStoreAction::ENoAction : ERenderTargetStoreAction::EStore; + RenderTargetsInfo.DepthTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingDepth() ? StoreAction : ERenderTargetStoreAction::ENoAction; + RenderTargetsInfo.StencilTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingStencil() ? StoreAction : ERenderTargetStoreAction::ENoAction; +} +``` + +### ParallelRendering +AnisotropyPass支持并行渲染,并行渲染的判断逻辑为 +```c++ +const bool bEnableParallelBasePasses = GRHICommandList.UseParallelAlgorithms() && CVarParallelBasePass.GetValueOnRenderThread(); +``` +看得出判断条件是: +1. 显卡是否支持并行渲染。 +2. CVar(r.ParallelBasePass)是否开启并行渲染。 + +从AnisotropyPass可以看得出并行渲染与一般渲染的差别在于: +1. FRenderTargetBinding绑定时的ERenderTargetLoadAction不同,**并行为ELoad**;**普通渲染为EClear**。 +2. 调用AddPass添加了**ERDGPassFlags::SkipRenderPass**标记。 +3. 并行渲染会在AddPass中构建**FRDGParallelCommandListSet ParallelCommandListSet**,并作为传入**DispatchDraw**;普通渲染传递nullptr。 +4. 普通渲染会额外调用**SetStereoViewport(RHICmdList, View);**,本质是调用RHICmdList.SetViewport来设置View。 + +### Code +```c++ +RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderAnisotropyPass); +SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderAnisotropyPass, FColor::Emerald); +SCOPE_CYCLE_COUNTER(STAT_AnisotropyPassDrawTime); +RDG_GPU_STAT_SCOPE(GraphBuilder, RenderAnisotropyPass); + +for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) +{ + FViewInfo& View = Views[ViewIndex]; + + if (View.ShouldRenderView()) + { + FParallelMeshDrawCommandPass& ParallelMeshPass = View.ParallelMeshDrawCommandPasses[EMeshPass::AnisotropyPass]; + + if (!ParallelMeshPass.HasAnyDraw()) + { + continue; + } + + View.BeginRenderView(); + + auto* PassParameters = GraphBuilder.AllocParameters(); + PassParameters->View = View.GetShaderParameters(); + PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneTextures.Depth.Target, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilNop); + + ParallelMeshPass.BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams); + if (bDoParallelPass) + { + AddClearRenderTargetPass(GraphBuilder, SceneTextures.GBufferF); + + PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.GBufferF, ERenderTargetLoadAction::ELoad); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("AnisotropyPassParallel"), + PassParameters, + ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass, + [this, &View, &ParallelMeshPass, PassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList) + { + FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_AnisotropyPass), View, FParallelCommandListBindings(PassParameters)); + + ParallelMeshPass.DispatchDraw(&ParallelCommandListSet, RHICmdList, &PassParameters->InstanceCullingDrawParams); + }); + } + else + { + PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.GBufferF, ERenderTargetLoadAction::EClear); + + GraphBuilder.AddPass( + RDG_EVENT_NAME("AnisotropyPass"), + PassParameters, + ERDGPassFlags::Raster, + [this, &View, &ParallelMeshPass, PassParameters](FRHICommandList& RHICmdList) + { + SetStereoViewport(RHICmdList, View); + + ParallelMeshPass.DispatchDraw(nullptr, RHICmdList, &PassParameters->InstanceCullingDrawParams); + }); + } + } +} +``` \ No newline at end of file diff --git a/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/GBuffer&Material&BasePass.md b/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/GBuffer&Material&BasePass.md index 61641e1..be5d9a8 100644 --- a/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/GBuffer&Material&BasePass.md +++ b/03-UnrealEngine/卡通渲染相关资料/渲染功能/ShaderModel/GBuffer&Material&BasePass.md @@ -32,6 +32,7 @@ OutGBufferD = GBuffer.CustomData OutGBufferE = GBuffer.PrecomputedShadowFactors (GBT_Unorm_8_8_8_8) TargetVelocity / OutGBufferF = velocity / tangent (默认不开启 带有深度<开启Lumen与距离场 或者 开启光线追踪> GBC_Raw_Float_16_16_16_16 不带深度 GBC_Raw_Float_16_16) TargetSeparatedMainDirLight = SingleLayerWater相关 (有SingleLayerWater才会开启 GBC_Raw_Float_11_11_10) +OutGBufferF = Anisotropy // 0..1, 2 bits, use CastContactShadow(GBuffer) or HasDynamicIndirectShadowCasterRepresentation(GBuffer) to extract half PerObjectGBufferData;