Forward Shading Pipeline
The Two Tracks: Desktop Forward & Mobile Forward双轨制:桌面前向与移动前向
Contrary to a common assumption, Unreal Engine 5.6 does not have a dedicated ForwardShadingRenderer.cpp.
Forward shading exists on two separate tracks, each serving very different hardware targets:
与常见认知不同,UE 5.6 并没有独立的 ForwardShadingRenderer.cpp。
前向渲染以两条独立轨道运行,分别服务于截然不同的硬件目标:
Desktop Forward桌面前向
- Controlled by
IsForwardShadingEnabled(ShaderPlatform) - 由
IsForwardShadingEnabled(ShaderPlatform)控制 - Lives inside FDeferredShadingSceneRenderer
- 存在于 FDeferredShadingSceneRenderer 内部
- Skips GBuffer writes; lighting computed in base pass shader using Clustered Light Grid
- 跳过 GBuffer 写入;在 Base Pass 着色器中使用 Clustered Light Grid 计算光照
- Targets PC/Console VR where deferred shading is problematic with MSAA
- 针对 PC/主机 VR 场景,延迟着色在此场景下与 MSAA 不兼容
Mobile Forward (Primary focus)移动端前向(重点)
- Owned by FMobileSceneRenderer
- 由 FMobileSceneRenderer 管理
- Fully separate renderer class — not a branch of FDeferredShadingSceneRenderer
- 完全独立的渲染器类,不是 FDeferredShadingSceneRenderer 的分支
- Designed to exploit TBDR (Tile-Based Deferred Rendering) hardware on iOS/Android
- 专为利用 iOS/Android 上的 TBDR(基于瓦片的延迟渲染)硬件而设计
- Can optionally switch to Mobile Deferred via
IsMobileDeferredShadingEnabled() - 可通过
IsMobileDeferredShadingEnabled()可选地切换到移动端延迟着色
Desktop Forward: A Branch Inside the Deferred Renderer桌面前向:延迟渲染器内的分支
When r.ForwardShading=1 is set on PC, FDeferredShadingSceneRenderer skips the
GBuffer entirely and computes lighting per-pixel inside the base pass using
GetForwardDirectLightingSplit() from ForwardLightingCommon.ush.
The key conditional that drives most of the pipeline differences is:
在 PC 上设置 r.ForwardShading=1 时,FDeferredShadingSceneRenderer 完全跳过 GBuffer,
在 Base Pass 内使用 ForwardLightingCommon.ush 中的 GetForwardDirectLightingSplit()
逐像素计算光照。驱动大多数管线差异的关键条件判断是:
// DeferredShadingRenderer.cpp — multiple call sites if (IsForwardShadingEnabled(ShaderPlatform)) { // Forward-specific early paths: RenderShadowDepthMaps(...); // Shadows BEFORE base pass RenderForwardShadowProjections(...); // Pre-render shadow mask texture ComputeVolumetricFog(...); // Fog also before base pass } else { // Deferred path: shadows run AFTER base pass }
The most important structural difference: in desktop forward, shadow maps are rendered before
the base pass, and their results are written into a screen-space ForwardScreenSpaceShadowMask texture.
The base pass pixel shader then samples this texture at GetForwardDynamicShadowFactors(ScreenUV)
to apply pre-computed shadowing. This avoids the need for per-light shadow projection passes after lighting.
最重要的结构性差异:桌面前向中阴影贴图在 Base Pass 之前渲染,结果写入屏幕空间的
ForwardScreenSpaceShadowMask 纹理。Base Pass 像素着色器通过
GetForwardDynamicShadowFactors(ScreenUV) 采样此纹理以应用预计算阴影,
避免了光照后逐光源投影 Pass 的需要。
FMobileSceneRenderer — Constructor & Key FlagsFMobileSceneRenderer — 构造函数与关键标志
All mobile pipeline decisions are made in the constructor (MobileShadingRenderer.cpp:303),
evaluated once per frame before any rendering work starts. Understanding these flags is the key to
understanding every branch in the mobile renderer.
所有移动端管线决策都在构造函数(MobileShadingRenderer.cpp:303)中完成,
在任何渲染工作开始前每帧计算一次。理解这些标志是理解移动端渲染器每个分支的关键。
FMobileSceneRenderer::FMobileSceneRenderer(...) : FSceneRenderer(InViewFamily, HitProxyConsumer) , bGammaSpace(!IsMobileHDR()) // LDR = no tonemap pass needed , bDeferredShading(IsMobileDeferredShadingEnabled(ShaderPlatform)) // Mobile Deferred toggle , bRequiresDBufferDecals(IsUsingDBuffers(ShaderPlatform)) , bEnableClusteredLocalLights(MobileForwardEnableLocalLights(ShaderPlatform)) , bEnableClusteredReflections(MobileForwardEnableClusteredReflections(ShaderPlatform)) { bIsFullDepthPrepassEnabled = (Scene->EarlyZPassMode == DDM_AllOpaque || Scene->EarlyZPassMode == DDM_AllOpaqueNoVelocity); bTonemapSubpass = IsMobileTonemapSubpassEnabled(...); // Inline tonemap in base pass (Vulkan) bTonemapSubpassInline = ...; bRequiresSceneDepthAux = MobileRequiresSceneDepthAux(...); // iOS needs SceneDepthAux RT }
| Flag标志 | Condition条件 | Effect效果 |
|---|---|---|
| bDeferredShading | IsMobileDeferredShadingEnabled() |
Routes to RenderDeferredSinglePass/MultiPass instead of RenderForward路由到 RenderDeferredSinglePass/MultiPass 而非 RenderForward |
| bIsFullDepthPrepassEnabled | DDM_AllOpaque / DDM_AllOpaqueNoVelocity |
Enables full Z-prepass; depth is loaded (not cleared) in main pass — critical for TBDR depth fetch启用完整深度预通道;主 Pass 加载而非清除深度——对 TBDR 深度读取至关重要 |
| bEnableClusteredLocalLights | MobileForwardEnableLocalLights() |
Builds a clustered light grid; enables per-pixel local light loops in the pixel shader构建聚簇光源网格;在像素着色器中启用逐像素局部光源循环 |
| bTonemapSubpass | Vulkan + r.Mobile.TonemapSubpass |
Tonemapping runs as a subpass inside the same render pass — eliminates one full frame buffer write色调映射作为同一渲染通道内的子通道运行——消除一次完整帧缓冲写入 |
| bRequiresMultiPass | Set in InitViews()在 InitViews() 中设置 |
Translucency or scene depth access forces a second render pass半透明或场景深度访问强制第二个渲染通道 |
Mobile Render() Main Loop移动端 Render() 主循环
Unlike the deferred renderer, the mobile Render() loop is significantly more compact (under 600 lines of active logic vs. 2300+). The most critical structural difference from deferred rendering is that shadows are rendered before the base pass, not after. This is essential because forward shading needs shadow data available during material evaluation.
与延迟渲染器不同,移动端 Render() 循环更为紧凑(活跃逻辑不足 600 行,而延迟端超过 2300 行)。 与延迟渲染最关键的结构性差异是:阴影在 Base Pass 之前渲染,而非之后。 这是必须的,因为前向着色需要在材质评估期间就能获取阴影数据。
00Visibility & Setup可见性与初始化
InitViews()— visibility, MeshDrawCommands, setsbRequiresMultiPassInitViews()— 可见性、MeshDrawCommands 生成,设置bRequiresMultiPassGPUScene.UploadDynamicPrimitiveShaderDataForView()— GPU primitive dataGPUScene.UploadDynamicPrimitiveShaderDataForView()— GPU 图元数据上传GatherAndSortLights()+PrepareForwardLightData()— synchronous (no async task unlike deferred)GatherAndSortLights()+PrepareForwardLightData()— 同步执行(不像延迟端有异步任务)- Sky atmosphere LUT generation if needed
- 按需生成天空大气 LUT
01Lights & Shadows — Before Base Pass灯光与阴影 — Base Pass 之前
RenderShadowDepthMaps()— all shadow maps rendered before the base passRenderShadowDepthMaps()— 所有阴影贴图在 Base Pass 之前渲染ComputeVolumetricFog()— volumetric fog also pre-computed for forwardComputeVolumetricFog()— 体积雾同样在前向路径中预计算RenderMobileLocalLightsBuffer()— Local Light Prepass: a Compute shader tiles the screen and writes merged local light data into two textures (LocalLightTextureA: RGB light color,LocalLightTextureB: packed direction + specular scale). This is only possible withbIsFullDepthPrepassEnabledsince it needs depth.RenderMobileLocalLightsBuffer()— 局部光源预通道:Compute Shader 对屏幕进行分块,将合并后的局部光源数据写入两张纹理(LocalLightTextureA:RGB 光色,LocalLightTextureB:打包方向 + 高光缩放)。此通道仅在bIsFullDepthPrepassEnabled时可用,因为它需要深度缓冲。
02Full Depth Prepass (Conditional)完整深度预通道(条件执行)
When bIsFullDepthPrepassEnabled is true, RenderFullDepthPrepass() writes all opaque depth.
This enables two important optimizations downstream:
当 bIsFullDepthPrepassEnabled 为 true 时,RenderFullDepthPrepass() 写入所有不透明深度。
这为后续开启两个重要优化:
- The main base pass loads depth as read-only, which on TBDR means the depth attachment stays in on-chip memory between the prepass and main pass — zero DRAM bandwidth for depth.
- 主 Base Pass 以只读方式加载深度,这意味着在 TBDR 上深度附件在预通道和主通道之间保持在片上内存中——深度带宽为零。
- The
RenderMobileLocalLightsBuffer()prepass can sample depth to compute per-tile light lists. RenderMobileLocalLightsBuffer()预通道可以采样深度以计算每瓦片光源列表。- After the prepass, HZB is built (
RenderHZB()) for occlusion culling. - 预通道结束后,构建 HZB(
RenderHZB())用于遮挡剔除。
03RenderForward — The Single-Pass DesignRenderForward — 单 Pass 设计
RenderForward() dispatches to either RenderForwardSinglePass()
or RenderForwardMultiPass() depending on bRequiresMultiPass.
The single-pass variant is the default and the architecturally important one:
RenderForward() 根据 bRequiresMultiPass 分发到
RenderForwardSinglePass() 或 RenderForwardMultiPass()。
单 Pass 变体是默认路径,也是架构上最重要的:
// MobileShadingRenderer.cpp:1782 — the entire opaque+translucency pipeline is ONE RDG pass GraphBuilder.AddPass( RDG_EVENT_NAME("SceneColorRendering"), PassParameters, ERDGPassFlags::Raster | ERDGPassFlags::NeverMerge, // NeverMerge: per-view passes must stay separate [this, ...](FRHICommandList& RHICmdList) { RenderMaskedPrePass(RHICmdList, View, ...); // Depth write for masked materials RenderMobileBasePass(RHICmdList, View, ...); // Opaque + sky: material eval + lighting + fog RHICmdList.NextSubpass(); // TBDR: depth now readable as framebuffer fetch RenderDecals(RHICmdList, View, ...); RenderModulatedShadowProjections(...); RenderFog(RHICmdList, View); // Pixel fog — uses subpass depth fetch RenderTranslucency(RHICmdList, View, ...); // Translucency also in same render pass PreTonemapMSAA(RHICmdList, SceneTextures); // Optional: inline tonemap subpass (Vulkan) });
The RHICmdList.NextSubpass() call is the hardware key. On TBDR GPUs this signals the driver
that subsequent draw calls may read the depth buffer from the same render pass as a framebuffer fetch
— without any round-trip to DRAM. This is how the fog pass reads per-pixel depth without
sampling a depth texture.
RHICmdList.NextSubpass() 调用是硬件关键点。在 TBDR GPU 上,这向驱动程序发出信号:
后续绘制调用可以通过帧缓冲读取从同一渲染通道读取深度缓冲区,
无需任何 DRAM 往返。这就是雾效 Pass 在不采样深度纹理的情况下读取逐像素深度的方式。
04Post Processing后处理
AddMobilePostProcessingPasses()— mobile-specific post chain: TAA, Bloom, DoF, TonemapAddMobilePostProcessingPasses()— 移动端专属后处理链:TAA、Bloom、DoF、色调映射- In LDR mode (
bGammaSpace), tonemap runs inline as a subpass — eliminating a full framebuffer resolve - LDR 模式(
bGammaSpace)下,色调映射以子通道内联运行——消除完整帧缓冲解析 - Eye adaptation via
IsMobileEyeAdaptationEnabled()— separate histogram pass if enabled - 通过
IsMobileEyeAdaptationEnabled()控制曝光自适应——启用时有独立直方图 Pass
Light Data Architecture光照数据架构
Mobile forward uses three distinct mechanisms to deliver light data to shaders, reflecting the tension between shader simplicity and supporting more lights:
移动端前向使用三种不同机制向着色器传递光照数据,反映了着色器简洁性与支持更多光源之间的权衡:
1. Directional Light — Uniform Buffer1. 方向光 — Uniform Buffer
The primary directional light is always passed via MobileDirectionalLight uniform buffer
(FMobileDirectionalLightShaderParameters). The pixel shader evaluates it first
with a direct MobileDirectionalLight.DirectionalLightDirectionAndShadowTransition access
at line 1044 of MobileBasePassPixelShader.usf. No light loop required —
it's hardcoded as the primary light source.
主方向光始终通过 MobileDirectionalLight uniform buffer(FMobileDirectionalLightShaderParameters)传递。
像素着色器首先在 MobileBasePassPixelShader.usf 第 1044 行通过直接访问
MobileDirectionalLight.DirectionalLightDirectionAndShadowTransition 对其进行评估。
不需要光源循环——它被硬编码为主光源。
2. Local Lights — Three Modes2. 局部光源 — 三种模式
Local (point/spot) lights are handled by one of three exclusive modes, selected at shader compile time
via MERGED_LOCAL_LIGHTS_MOBILE and ENABLE_CLUSTERED_LIGHTS defines:
局部(点光源/聚光灯)光源通过三种互斥模式之一处理,在着色器编译时通过
MERGED_LOCAL_LIGHTS_MOBILE 和 ENABLE_CLUSTERED_LIGHTS 定义来选择:
| Mode | Define宏定义 | Mechanism机制 | Trade-off权衡 |
|---|---|---|---|
| Prepass Buffer预通道缓冲 | MERGED_LOCAL_LIGHTS_MOBILE == 1 |
Reads from LocalLightTextureA/B written by RenderMobileLocalLightsBuffer(). All local lights merged into single direction + color per pixel.从 RenderMobileLocalLightsBuffer() 写入的 LocalLightTextureA/B 中读取。所有局部光源每像素合并为单一方向和颜色。 |
Lowest ALU cost in base pass; requires full depth prepassBase Pass ALU 开销最低;需要完整深度预通道 |
| Clustered Merge聚簇合并 | MERGED_LOCAL_LIGHTS_MOBILE == 2 |
Iterates clustered light grid per pixel, merges contributions via MergeLocalLights() into one synthetic light direction每像素遍历聚簇光源网格,通过 MergeLocalLights() 将贡献合并为一个合成光照方向 |
Better quality than mode 1; heavier per-pixel ALU质量优于模式 1;每像素 ALU 开销更重 |
| Full Clustered完整聚簇 | ENABLE_CLUSTERED_LIGHTS |
Full per-pixel light loop via AccumulateLightGridLocalLighting() — similar to desktop deferred clustered, but runs inside the forward base pass通过 AccumulateLightGridLocalLighting() 进行完整的逐像素光源循环——类似桌面延迟聚簇,但在前向 Base Pass 内运行 |
Highest quality; most expensive per-pixel; benefits from clustered culling最高质量;每像素开销最大;受益于聚簇剔除 |
MobileBasePassPixelShader.usf — The All-in-One ShaderMobileBasePassPixelShader.usf — 全合一着色器
This is arguably the most important file in the mobile renderer. In forward mode, a single invocation of Main() (line 302) performs what the deferred renderer spreads across three stages: material evaluation, direct lighting, and reflection/indirect lighting.
这可以说是移动端渲染器中最重要的文件。在前向模式下,Main()(第 302 行)的单次调用 完成了延迟渲染器分布在三个阶段的工作:材质评估、直接光照以及反射/间接光照。
// MobileBasePassPixelShader.usf:302 — the combined forward shader void Main(FVertexFactoryInterpolantsVSToPS Interpolants, ..., out HALF4_TYPE OutColor : SV_Target0) // Forward: direct color output // If MOBILE_USE_GBUFFER: also outputs OutGBufferA/B/C/D (Mobile Deferred path) { // 1. Evaluate material expressions → GBuffer struct (even in forward mode) FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(...); FGBufferData GBuffer = GetGBufferData(...); // 2. Sample pre-computed indirect lighting (lightmaps / SH cache) GetPrecomputedIndirectLightingAndSkyLight(..., DiffuseIndirectLighting, IndirectIrradiance); // 3. Direct lighting — directional light (hardcoded) AccumulateDirectionalLighting(GBuffer, ..., DirectLighting); // 4. Local lights — one of three modes (compile-time select) // MERGED_LOCAL_LIGHTS_MOBILE==1: read LocalLightTexture // MERGED_LOCAL_LIGHTS_MOBILE==2: MergeLocalLights() from grid // ENABLE_CLUSTERED_LIGHTS: AccumulateLightGridLocalLighting() // 5. Reflection IBL AccumulateReflection(GBuffer, ..., GridIndex, DirectLighting); // 6. Emissive + fog (vertex fog via interpolant — NOT a separate pass!) Color += GetMaterialEmissive(PixelMaterialInputs); half4 VertexFog = BasePassInterpolants.VertexFog; // Fog packed as VS→PS interpolant Color = Color * VertexFog.a + VertexFog.rgb; // Apply fog in-shader }
BasePassInterpolants.VertexFog. This is one of the bandwidth advantages of forward shading that is impossible in deferred (where geometry data is unavailable at the lighting stage).
前向渲染中雾效是免费的。注意雾效是作为顶点插值值在像素着色器末尾应用的——没有单独的雾效 Pass,没有额外的渲染目标,没有额外的带宽开销。顶点着色器预先计算雾密度,通过 BasePassInterpolants.VertexFog 传递到像素阶段。这是前向着色带宽优势之一,在延迟渲染中(光照阶段无法获取几何数据)是不可能实现的。
ForwardLightingCommon.ush — Desktop Forward Light LoopForwardLightingCommon.ush — 桌面前向光照循环
This header is used by the PC forward shading path (and by translucency in the deferred renderer). It implements the full per-pixel light loop that the deferred GBuffer path avoids by separating geometry from lighting. The key function is GetForwardDirectLightingSplit():
此头文件用于 PC 前向着色路径(以及延迟渲染器中的半透明)。 它实现了完整的逐像素光照循环——延迟 GBuffer 路径通过将几何与光照分离而避免了这一点。 关键函数是 GetForwardDirectLightingSplit():
// ForwardLightingCommon.ush:137 — called from base pass pixel shader on desktop forward FDeferredLightingSplit GetForwardDirectLightingSplit( uint2 PixelPos, uint GridIndex, float3 WorldPosition, ...) { // 1. Directional light — with pre-sampled shadow mask float4 DynamicShadowFactors = GetForwardDynamicShadowFactors(ScreenUV); // ForwardScreenSpaceShadowMaskTexture was written before the base pass // 2. Optional VSM shadows for directional light #if VIRTUAL_SHADOW_MAP VirtualShadowMapSample = TraceDirectional(ForwardLightStruct.DirectionalLightVSM, ...); DynamicShadowFactor *= VirtualShadowMapSample.ShadowFactor; #endif // 3. Local lights loop — reads from clustered light grid FCulledLightsGridHeader Header = GetCulledLightsGridHeader(GridIndex); uint NumLights = min(Header.NumLights, GetMaxLightsPerCell()); // MaxCulledLightsPerCell LOOP for (uint i = 0; i < NumLights; i++) { FLocalLightData LocalLight = GetLocalLightDataFromGrid(Header.DataStartIndex + i, EyeIndex); // Optional per-light VSM shadow if (LocalLight.Internal.VirtualShadowMapId != INDEX_NONE) DynamicShadowFactor *= SampleVirtualShadowMapLocal(...); DirectLighting += GetDynamicLightingSplit(..., LightData, LightAttenuation, ...); } return DirectLighting; }
The critical insight here: GetMaxLightsPerCell() returns
ForwardLightStruct.MaxCulledLightsPerCell, which is set at CPU-side light grid construction.
This is not a hard limit of 4 — the number of local lights per froxel cell is
dynamically determined by the light grid. VR/forward mode typically caps this lower for performance,
but the architecture itself supports arbitrary counts up to the grid budget.
关键洞察:GetMaxLightsPerCell() 返回 ForwardLightStruct.MaxCulledLightsPerCell,
该值在 CPU 端光源网格构建时设置。这并非固定的 4 个光源限制——每个 Froxel 单元的局部光源数量由光源网格动态决定。
VR/前向模式出于性能通常将其限制得更低,但架构本身支持不超过网格预算的任意数量。
TBDR Hardware Analysis — Why Forward Wins on MobileTBDR 硬件博弈分析 — 前向渲染为何赢在移动端
Mobile GPUs (Apple A-series, Qualcomm Adreno, ARM Mali) use Tile-Based Deferred Rendering (TBDR) architecture, fundamentally different from desktop's Immediate Mode Rendering (IMR). Understanding this hardware difference is the entire reason UE's mobile renderer exists as a separate class.
移动 GPU(苹果 A 系列、高通 Adreno、ARM Mali)使用基于瓦片的延迟渲染(TBDR)架构, 与桌面端的即时模式渲染(IMR)有根本性差异。理解这种硬件差异,正是 UE 移动端渲染器作为独立类存在的全部原因。
IMR (Desktop GPU)IMR(桌面 GPU)
- Processes triangles immediately as they arrive
- 三角形到来后立即处理
- Framebuffer lives in VRAM (~500 GB/s bandwidth)
- 帧缓冲存储在 VRAM(~500 GB/s 带宽)
- GBuffer bandwidth: ~300 MB/frame at 1080p (4 targets × 8 bytes × 1920×1080)
- GBuffer 带宽:1080p 下约 300 MB/帧(4 目标 × 8 字节 × 1920×1080)
- Cheap; VRAM bandwidth is massive
- 开销低;VRAM 带宽极大
TBDR (Mobile GPU)TBDR(移动 GPU)
- Divides screen into tiles (~16×16 or 32×32 pixels)
- 将屏幕分割为瓦片(约 16×16 或 32×32 像素)
- All geometry for a tile is buffered, then the entire tile is shaded in on-chip SRAM (~100–400 GB/s)
- 一个瓦片的所有几何体被缓冲,然后整个瓦片在片上 SRAM(~100–400 GB/s)中着色
- Tile result is written to DRAM only once at end — massive bandwidth saving
- 瓦片结果仅在末尾写入 DRAM 一次——节省大量带宽
- Reading back from framebuffer (GBuffer pass → lighting pass) forces a tile flush to DRAM — fatal for performance
- 从帧缓冲读回(GBuffer 通道 → 光照通道)迫使瓦片刷新到 DRAM——对性能致命
A deferred G-Buffer pass at 1080p on mobile writes approximately:
移动端 1080p 下延迟 GBuffer 通道大约写入:
// Approximate G-Buffer bandwidth at 1080p GBufferA (Normal + ShadingModelID) = 1920 × 1080 × 4 bytes = ~8 MB (R8G8B8A8) GBufferB (Metallic/Spec/Rough) = 1920 × 1080 × 4 bytes = ~8 MB (R8G8B8A8) GBufferC (BaseColor + AO) = 1920 × 1080 × 4 bytes = ~8 MB (R8G8B8A8) SceneDepth (read in lighting pass) = 1920 × 1080 × 4 bytes = ~8 MB (R32) // Write + read back = ~64 MB per frame through off-chip DRAM // At 60 FPS: ~3.8 GB/s of GBuffer traffic alone // Mobile LPDDR5 typical bandwidth: ~50 GB/s total — GBuffer consumes ~8% just for base data
The ESubpassHint::DepthReadSubpass set on BasePassRenderTargets
and RHICmdList.NextSubpass() are the API-level signals that enable the driver to
keep framebuffer data on-chip across the depth-write subpass and the depth-read subpass,
without ever touching DRAM in between.
在 BasePassRenderTargets 上设置的 ESubpassHint::DepthReadSubpass
以及 RHICmdList.NextSubpass() 是让驱动程序能够在深度写子通道和深度读子通道之间
将帧缓冲数据保持在片上的 API 级信号,期间完全不接触 DRAM。
Key Console Variables关键控制台变量
| CVar | Default默认值 | Effect效果 |
|---|---|---|
| r.ForwardShading | 0 | Enables desktop forward shading path in FDeferredShadingSceneRenderer启用 FDeferredShadingSceneRenderer 中的桌面前向路径 |
| r.Mobile.ForceDepthResolve | 0 | Forces a depth resolve by drawing with the depth texture — workaround for some devices强制通过绘制深度纹理来解析深度——某些设备的变通方案 |
| r.Mobile.AdrenoOcclusionMode | 0 | Mode 1: defer occlusion queries to after translucency + flush — helps Adreno in GL mode模式 1:将遮挡查询延迟到半透明和刷新之后——有助于 Adreno GL 模式 |
| r.Mobile.CustomDepthForTranslucency | 1 | Whether to render CustomDepth/Stencil if any translucency uses it如果半透明材质使用 CustomDepth/Stencil,是否渲染它 |
| r.SceneDepthHZBAsyncCompute | 0 | 0=sync, 1=async as soon as possible, 2=async after light grid compact pass0=同步,1=尽早异步,2=在光源网格紧凑 Pass 后异步 |
| r.AdrenoOcclusionUseFDM | 0 | Use FDM (Fragment Density Map) with Adreno occlusion mode — reduces overdraw on VR在 Adreno 遮挡模式下使用 FDM(片段密度贴图)——减少 VR 中的过度绘制 |
| r.shadow.ShadowMapsRenderEarly | 0 | Force early shadow rendering even on desktop deferred path (not compatible with VSM)在桌面延迟路径上强制早期阴影渲染(不兼容 VSM) |
Source Navigation源码导航
All paths relative to Engine/Source/Runtime/Renderer/Private/ or Engine/Shaders/Private/.
所有路径相对于 Engine/Source/Runtime/Renderer/Private/ 或 Engine/Shaders/Private/。
- MobileShadingRenderer.cpp:303FMobileSceneRenderer constructor — all pipeline flagsFMobileSceneRenderer 构造函数 — 所有管线标志
- MobileShadingRenderer.cpp:1025FMobileSceneRenderer::Render() — top-level mobile render loopFMobileSceneRenderer::Render() — 移动端顶层渲染循环
- MobileShadingRenderer.cpp:1667RenderForward() — dispatches to Single or Multi passRenderForward() — 分发到单 Pass 或多 Pass
- MobileShadingRenderer.cpp:1742RenderForwardSinglePass() — the single RDG pass that contains everythingRenderForwardSinglePass() — 包含所有内容的单个 RDG Pass
- MobileShadingRenderer.cpp:1611InitRenderTargetBindings_Forward() — MSAA/subpass RT setupInitRenderTargetBindings_Forward() — MSAA/子通道 RT 设置
- MobileLocalLightsBuffer.cppLocal Light Prepass — FLocalLightBufferCS/VS/PS, merges local lights into textures局部光源预通道 — 将局部光源合并到纹理
- MobileBasePassRendering.cppBase pass draw calls, shader permutation setup (
MERGED_LOCAL_LIGHTS_MOBILE)Base Pass 绘制调用,着色器排列组合设置 - MobileBasePassPixelShader.usf:302Main() — material + direct lighting + reflection + fog in one shaderMain() — 材质、直接光照、反射、雾效合一着色器
- ForwardLightingCommon.ush:137GetForwardDirectLightingSplit() — desktop forward full light loopGetForwardDirectLightingSplit() — 桌面前向完整光照循环
- LightGridCommon.ush:76GetMaxLightsPerCell() — dynamic per-cell light cap from ForwardLightStructGetMaxLightsPerCell() — 来自 ForwardLightStruct 的动态每单元光源上限
- DeferredShadingRenderer.cpp
IsForwardShadingEnabled()branches — desktop forward within deferred rendererIsForwardShadingEnabled()分支 — 延迟渲染器内的桌面前向