渲染系统 UE4 的渲染器是在其自身的渲染线程中执行的
这个渲染线程通常落后于游戏线程1到2帧
所以有一些类会将游戏线程上的状态信息连接到渲染线程中来 (通常以F开头)
FScene -- 表示游戏场景, 是 UWorld 的渲染器版本
FPrimitiveSceneProxy -- UPrimitiveComponent 的渲染器版本, 为渲染线程映射 UPrimitiveComponent 状态
FPrimitiveSceneInfo -- FPrimitiveSceneProxy 的状态, 只存在于渲染器
FViewInfo -- 当前屏幕视图的渲染器 对应游戏模块中的 FSceneView
FSceneViewState -- FViewInfo 的状态, 与游戏中 UPlayer 一一对应
FLightSceneProxy 与 FLightSceneInfo -- 跟 Primitive差不多
FPrimitiveSceneProxy 存在于引擎模块中, 有两个 API 比较重要
DrawDynamicElements -- 在与之相关的任何 Pass 中绘制该拥有动态相关性的代理物体
DrawStaticElements -- 在与游戏线程相连时绘制该拥有静态相关性的代理物体
这也说明 UE4 对几何体的渲染是分了 Static 和 Dynamic 分别来处理的
Static Render在 FPrimitiveSceneProxy
被放入场景时, 会调用其 DrawStaticElements
来收集 FStaticMeshElements
, 然后创建对应的 Draw Policy
放到 FScene
的 Draw List
里去。 Dynamic Render在判定 FPrimitiveSceneProxy
可见后即调用 DrawDynamicElements()
来收集 FMeshElements
【Tips】 Proxy 的意思为渲染模块在游戏模块中出现的代理, 实际存在于引擎模块中, 而非渲染模块中
材质在渲染时也需要连接游戏线程和渲染线程的接口
FMaterial -- 材质的接口, 提供属性的查询等 -- 纯虚类
FMaterialResoruce -- FMaterial 的一个具体实现, 对应 UMaterial
FMaterialRenderProxy -- 提供给渲染线程使用的代理
渲染流程 =============================================
【Pass_0】 Depth Only Pass 【Pass_1】 Base Pass 【Pass_2】 Issue Occlusion Queries 【Pass_3】 ShadowMap 【Pass_4】 Lighting 【Pass_5】 Fog 【Pass_6】 Post Processing
============================================= 【Tips】 基于 Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class FDeferredShadingSceneRenderer : public FSceneRenderer{ public : bool RenderPrePassViewDynamic (FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState) ; bool RenderPrePassView (FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState) ; bool RenderBasePass (FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, IPooledRenderTarget* ForwardScreenSpaceShadowMask) ; bool RenderBasePassView (FRHICommandListImmediate& RHICmdList, FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FDrawingPolicyRenderState& InDrawRenderState) ; void RenderOcclusion (FRHICommandListImmediate& RHICmdList) ; void FinishOcclusion (FRHICommandListImmediate& RHICmdList) void RenderShadowDepthMaps (FRHICommandListImmediate& RHICmdList) ; void RenderShadowDepthMapAtlases (FRHICommandListImmediate& RHICmdList) ; virtual void Render (FRHICommandListImmediate& RHICmdList) override ; void RenderLights (FRHICommandListImmediate& RHICmdList) ; virtual void Render (FRHICommandListImmediate& RHICmdList) override ; bool RenderFog (FRHICommandListImmediate& RHICmdList, const FLightShaftsOutput& LightShaftsOutput) ; virtual void Render (FRHICommandListImmediate& RHICmdList) override ; }
【Pass_0】 Depth Only Pass 深度处理阶段
绘制 Depth 到 Depth_Buffer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 bool RenderPrePassView (FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState) { { bDirty |= RenderPrePassViewDynamic (); } return bDirty; } bool RenderPrePassViewDynamic (FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState) { foreach (mesh) { if (可见) { FDepthDrawingPolicyFactory::DrawDynamicMesh (); } } return true ; }
【Tips】 DrawingPolicyFactory
为绘制规则的工厂类
【Pass_1】 Base Pass 绘制 不透明的 和 Masked Material
属性的 Mesh
填充 G_Buffer
UE4 中的 G_Buffer
结构 (来知乎专栏_虚幻4渲染编程)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 bool RenderBasePass (FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, IPooledRenderTarget* ForwardScreenSpaceShadowMask) { bDirty |= RenderBasePassView (RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState); return bDirty; } bool RenderBasePassView (FRHICommandListImmediate& RHICmdList, FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FDrawingPolicyRenderState& InDrawRenderState) { bDirty |= RenderBasePassStaticData (RHICmdList, View, DrawRenderState); RenderBasePassDynamicData (RHICmdList, View, DrawRenderState, bDirty); return bDirty; }
此时 Shader
文件可从下面代码
1 2 3 4 5 6 7 8 #define IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,bEnableSkyLight,SkyLightName) \ typedef TBasePassPS<LightMapPolicyType, bEnableSkyLight> TBasePassPS##LightMapPolicyName##SkyLightName; \ IMPLEMENT_MATERIAL_SHADER_TYPE(template<> ,TBasePassPS##LightMapPolicyName##SkyLightName, \ TEXT(" /Engine/Private/BasePassPixelShader.usf" ), \ TEXT("MainPS" ),SF_Pixel);
即 /Engine/Private/BasePassPixelShader.usf 696
1 2 3 4 5 6 7 8 9 10 11 void FPixelShaderInOut_MainPS ( FVertexFactoryInterpolantsVSToPS Interpolants, FBasePassInterpolantsVSToPS BasePassInterpolants, in FPixelShaderIn In, inout FPixelShaderOut Out) { }
这就是 Bass Pass 的 着色器入口了
【Pass_2】 Issue Occlusion Queries 遮挡查询, 为下一帧的可见性判断提供信息
ue4 的遮挡查询是对包围盒进行深度测试来判断的
1 2 void RenderOcclusion (FRHICommandListImmediate& RHICmdList) {}void FinishOcclusion (FRHICommandListImmediate& RHICmdList) {}
【Pass_3】 ShadowMap 阴影计算
1 2 void RenderShadowDepthMaps (FRHICommandListImmediate& RHICmdList) {}void RenderShadowDepthMapAtlases (FRHICommandListImmediate& RHICmdList) {}
【Pass_4】 Lighting 光照计算
首先预处理 延迟贴花 SSAO 等, 然后再进行光照计算
UE4 的光照计算采用 TBDR (Tiled Based Deferred Rendering)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void FDeferredShadingSceneRenderer::Render (FRHICommandListImmediate& RHICmdList) { RHICmdList.SetCurrentStat (GET_STATID (STAT_CLM_Lighting)); RenderLights (RHICmdList); RHICmdList.SetCurrentStat (GET_STATID (STAT_CLM_AfterLighting)); }
然后是处理光照的着色器入口
1 2 3 4 5 6 7 8 9 10 [numthreads (THREADGROUP_SIZEX, THREADGROUP_SIZEY, 1 )] void TiledDeferredLightingMain ( uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID) { }
【Pass_5】 Fog 雾计算
非透明表面逐像素计算 Fog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void FDeferredShadingSceneRenderer::Render (FRHICommandListImmediate& RHICmdList) { if (ShouldRenderFog (ViewFamily)) { SCOPE_CYCLE_COUNTER (STAT_FDeferredShadingSceneRenderer_RenderFog); RenderFog (RHICmdList, LightShaftOutput); ServiceLocalQueue (); } } bool RenderFog (FRHICommandListImmediate& RHICmdList, const FLightShaftsOutput& LightShaftsOutput) { }
【Pass_6】 Post Processing 后处理效果
1 2 3 4 5 6 7 8 9 10 11 void FDeferredShadingSceneRenderer::Render (FRHICommandListImmediate& RHICmdList) { ResolveSceneColor (RHICmdList); GetRendererModule ().RenderPostResolvedSceneColorExtension (RHICmdList, SceneContext); CopySceneCaptureComponentToTarget (RHICmdList); }
【Tips】 UE4 移动端似乎只有 Forward Rendering -- 没有 深度渲染器 和 GBuffer