--- title: 剖析虚幻渲染体系(05)- 光源和阴影 date: 2024-02-08 17:48:39 excerpt: tags: rating: ⭐ --- # 前言 https://www.cnblogs.com/timlly/p/14817455.html # Shader体系 ## Shader模块层级 **第一梯队**的shader模块是**最底层最基础的模块**,这些模块不会引用其它模块,但会被其它很多模块引用。这些模块主要有: - BasePassCommon.ush - BRDF.ush - CapsuleLight.ush - Common.ush - CommonViewUniformBuffer.ush - Definitions.usf - FP16Math.ush - Platform.ush - ShaderVersion.ush - LightGridCommon.ush - LocalVertexFactoryCommon.ush - ShadingCommon.ush - ShadowDepthCommon.ush - ShadowProjectionCommon.ush - SHCommon.ush - (......) **第二梯队**的**重要或基础模块**会引用第一梯队的基础模块,但也会被其它梯队或模块引用: - BasePassVertexCommon.ush - CapsuleLightIntegrate.ush - DeferredLightingCommon.ush - DeferredShadingCommon.ush - LocalVertexFactory.ush - MaterialTemplate.ush - RectLight.ush - RectLightIntegrate.ush - ShadingModels.ush - ShadingModelsMaterial.ush - VertexFactoryCommon.ush - (......) 最后是**第三梯队**的模块,重要模块的实现,会引用第一、第二梯队的模块: - BasePassPixelShader.usf - BasePassVertexShader.usf - CapsuleShadowShaders.usf - DeferredLightPixelShaders.usf - DeferredLightVertexShaders.usf - ShadowProjectionPixelShader.usf - ShadowProjectionVertexShader.usf - (......) ## Shader基础模块 - Platform.ush:主要定义了跟图形API(DirectX、OpenGL、Vulkan、Metal)和FEATURE_LEVEL相关的宏、变量及工具类接口。 - **Common.ush**:此模块主要包含了图形API或Feature Level相关的宏、类型、局部变量、静态变量、基础工具接口、常用Shader函数等。 - **Definitions.ush**:此模块主要是预先定义了一些常见的宏,防止其它模块引用时出现语法错误。 - **ShadingCommon.ush**:此模块主要是定义了材质所有ShaderModel,并提供了少量相关的工具类接口。 - **ShadingModels.ush**:此模块主要是着色模型以及光照计算相关的类型和辅助接口。 - **BasePassCommon.ush**:此模块定义了BasePass的一些变量、宏定义、插值结构体和工具类接口。 - **ShadingModelsMaterial.ush**:提供了根据材质和指定参数设置GBuffe的接口。 - BRDF.ush:双向反射分布函数模块,提供了很多基础光照算法及相关辅助接口。 - VertexFactoryCommon.ush:此模块主要定义了顶点变换相关的辅助接口。 - LocalVertexFactoryCommon.ush:局部顶点工厂通用模块,定义了顶点工厂的数据插值结构体及部分辅助接口。 - LocalVertexFactory.ush:局部顶点工厂模块,定义了骨骼蒙皮、顶点着色器等相关的数据类型和接口。 - BasePassVertexCommon.ush:此模块定义了一些BasePass通用的结构体、宏。 - 需要注意的是核心结构体`FGBufferData`,**它是通用的结构体,可用于BasePass和LightingPass的VS和PS之间,也可用于前向和延迟渲染中**。是最大数据集合体,在某些情况下,部分属性才有效,具体见**ShadingModelsMaterial.ush**的`SetGBufferForShadingModel`。 - **DeferredLightingCommon.ush**:此模块定义了延迟光照相关的通用的接口、宏、变量、类型等。 # BasePass 下面是`RenderBasePass`和`RenderBasePassViewParallel`并行渲染的逻辑: ```c++ bool FDeferredShadingSceneRenderer::RenderBasePass(FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, IPooledRenderTarget* ForwardScreenSpaceShadowMask, bool bParallelBasePass, bool bRenderLightmapDensity) { (......) FExclusiveDepthStencil::Type BasePassDepthStencilAccess_NoDepthWrite = FExclusiveDepthStencil::Type(BasePassDepthStencilAccess & ~FExclusiveDepthStencil::DepthWrite); // 并行模式 if (bParallelBasePass) { // 绘制任务等待. FScopedCommandListWaitForTasks Flusher(CVarRHICmdFlushRenderThreadTasksBasePass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0, RHICmdList); // 遍历所有view, 每个view渲染一次Base Pass. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { FViewInfo& View = Views[ViewIndex]; // Uniform Buffer TUniformBufferRef BasePassUniformBuffer; CreateOpaqueBasePassUniformBuffer(RHICmdList, View, ForwardScreenSpaceShadowMask, nullptr, nullptr, nullptr, BasePassUniformBuffer); // Render State FMeshPassProcessorRenderState DrawRenderState(View, BasePassUniformBuffer); SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState); const bool bShouldRenderView = View.ShouldRenderView(); if (bShouldRenderView) { Scene->UniformBuffers.UpdateViewUniformBuffer(View); // 执行并行渲染. RenderBasePassViewParallel(View, RHICmdList, BasePassDepthStencilAccess, DrawRenderState); } FSceneRenderTargets::Get(RHICmdList).BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, BasePassDepthStencilAccess, this->ViewFamily.EngineShowFlags.ShaderComplexity); RHICmdList.EndRenderPass(); (......) } } (......) } void FDeferredShadingSceneRenderer::RenderBasePassViewParallel(FViewInfo& View, FRHICommandListImmediate& ParentCmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FMeshPassProcessorRenderState& InDrawRenderState) { // 并行绘制的数据: 命令队列, 上下文, 渲染状态等. FBasePassParallelCommandListSet ParallelSet(View, ParentCmdList, CVarRHICmdBasePassDeferredContexts.GetValueOnRenderThread() > 0, CVarRHICmdFlushRenderThreadTasksBasePass.GetValueOnRenderThread() == 0 && CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() == 0, this, BasePassDepthStencilAccess, InDrawRenderState); // 触发并行绘制指令. View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(&ParallelSet, ParentCmdList); } ``` `RenderBasePass`是依靠`FScopedCommandListWaitForTasks`等待绘制指令完成。 ## BasePass渲染状态 我们知道BasePass是通过`FBasePassMeshProcessor`来收集很多shader绑定和绘制参数的,从Processor的过程中可以很容易知道,BasePass绘制时使用的VS和PS分别是`TBasePassVS`和`TBasePassPS`。 可知`TBasePassVS`提供了获取Shader绑定、更改编译环境和只编译指定的排列组合shader等接口,此外还拥有反射球、光照图类型等属性。下面是它的获取shader绑定的代码分析: ```c++ ```