延迟着色
Deferred Shading
延迟着色先用一遍几何 pass 把所有可见表面的材质参数写入多张渲染目标(G-buffer),再以后处理方式对这些存储值逐光源计算光照,从而把"几何可见性"与"光照"彻底解耦,并把材质与光源分离。它避免了着色的过度绘制、简化了着色器管理、天然适合贴花,但 G-buffer 占用显存和带宽,且难以直接支持透明和 MSAA。本页也覆盖前向渲染下限制光源影响范围的基础手段与"光照预通道 (light prepass)"类混合方案。
背景:多光源的代价(20 章引言)
- 多光源可写成支持多光源的单遍着色器,或多遍着色(每个光源一遍、结果累加)。后者每个着色器更简单,但 50 个光源意味着每个物体 50 遍顶点与像素处理;单遍着色器要包含所有光源类型并逐一判断,会很复杂。
- z-prepass 先只写深度、再完整着色,把"找可见几何"与"着色"分开,这一解耦思想贯穿全章;但几何要渲染两遍,曲面细分、蒙皮等昂贵网格代价可观;alpha 裁剪物体在每遍都要读纹理 alpha,否则只能留到第二遍。因此有时只在预通道画大遮挡物。AO、反射等屏幕空间效果也可能需要完整预通道。
- 限制光源范围:每个局部光源只影响一定半径的球(或锥等形状),超出后贡献可以忽略。半径常只由强度决定;Karis 指出光泽镜面材质会让半径变大,极光滑表面半径可能趋于无穷,只能改用环境贴图等。
- 每网格光源列表:相当于网格与光源的碰撞检测。问题是物体或光源移动会改变列表;为性能合并的大网格可能包含场景中大部分光源(可在合并后再按空间切分)。
- 烘焙到世界空间结构:《正当防卫 2》用俯视世界网格,每格 4 m × 4 m,存为 RGBA 纹理的一个纹素,每格最多 4 个光源;多层建筑会很快超出容量。
- 目标是高效处理动态网格与动态光源,并且性能可预测。《DOOM》(2016)部分关卡有 300 个可见光源,《奇点灰烬》某些场景有 10,000 个;粒子、光照探针也可视为短程光源。
基本流程(20.1 节)
前向着色在一遍中取材质参数并应用光源;延迟着色在第一遍几何 pass 中生成并存储可见物体的所有材质参数——位置(以深度存储)、法线、纹理坐标、各种材质参数——之后模型本身不再需要,光照以后处理方式施加到这些存储值上。
flowchart LR A["几何 pass: 光栅化所有不透明物体"] --> B["G-buffer: 深度, 法线, 反照率, 粗糙度, 金属度 ..."] B --> C["光照 pass: 对每个光源绘制覆盖其影响区域的代理几何"] C --> D["读取 G-buffer 计算光照并累加"] D --> E["前向渲染透明物体, 后处理"]
如上图。几何 pass 仍有过度绘制,但每次只是把值写入缓冲,比计算一组光源便宜得多;也减少了前向着色中 2×2 quad 部分在三角形外仍需完整着色的浪费——设想每个三角形只覆盖一个像素,前向着色会算 4 个完整样本丢掉 3 个,延迟着色的被丢弃样本代价低得多。
G-buffer(geometric buffer)可以存程序员需要的任何东西,每张是一个独立渲染目标,通常 3~5 张,也有多达 8 张的系统;目标越多带宽越大,越容易成为瓶颈。例如《彩虹六号:围攻》除深度与模板外使用 4 张 RT:世界法线 (RGB10)、基础色 (sRGB8)、金属度、光泽度、cavity、速度、GI 配置等。可用低精度或压缩减轻开销;法线常用世界空间八面体映射,精度高且编解码快。
光照 pass 的优化
逐光源绘制全屏四边形、每个像素判断是否在光源范围内,是最低效的用法,可能比前向着色还慢(多了 G-buffer 写和读)。改进:
- 计算光源球的屏幕包围矩形,只绘制这块四边形;画椭圆更紧。
- 利用深度:绘制粗略包围球网格;若球被深度缓冲挡住,则光源体积在最近表面之后,没有影响。一般地,若球在某像素处的最小与最大深度与最近表面不重叠,光源就影响不到该像素。"表面与光源的深度重叠测试"会在后续算法中反复出现。
优点
- 光照与材质强分离:每个着色器只负责参数提取或光照,更短更快,便于优化;寄存器用量决定占用率。新增一种光源或材质只需加一个着色器,而不是每种组合一个。
- 前向着色要么一个覆盖所有组合的巨型着色器(动态分支常慢很多),要么大量专用着色器(难生成和管理),并更频繁地切换着色器。
- 每个光源单独一遍时,内存中一次只需一张阴影贴图(但在后续按组评估光源的方案中这一优势消失)。
- 天然适合 贴花渲染。
局限
| 问题 | 说明与对策 |
|---|---|
| 材质单一 | 基础版只有一种参数固定的材质着色器;可逐像素存材质 ID 或掩码,按 ID 改变计算甚至改变 G-buffer 内容(例如同样 32 位一种材质存第二层颜色与混合因子,另一种存两个切线),代价是更复杂的着色器 |
| 显存与带宽 | G-buffer 很大、反复访问;用低精度、压缩缓解 |
| 透明 | 每像素只存一个表面;常规做法是不透明用延迟、透明用前向。早期系统需对透明物体应用全部光源;现在有光源剔除方案,也可存逐像素透明表面列表实现纯延迟,但常态是按需混合延迟与前向 |
| MSAA | 前向 N×MSAA 只需每像素 N 个深度和颜色样本;延迟若在 G-buffer 存全部样本,内存、填充率、计算都很贵。对策:边缘检测近似边缘覆盖、形态学后处理抗锯齿、时间抗锯齿;或检测含边缘的像素/瓦片,只对它们做多样本计算(用模板标记,或用计算着色器把边缘像素移到线程组内存列表里流式处理) |
光照预通道与 L-buffer(20.3 节开头)
早期混合方案在材质与光照存储之间折中:例如只有漫反射项受纹理影响时,先对每个光源分别累加漫反射与镜面项到L-buffer(常见为漫反射颜色加镜面强度,共 4 个值可用加法混合写入一张缓冲),最后读一次纹理颜色乘漫反射项再加镜面项。纹理只用一次,每个光源访问的 G-buffer 数据更少,省带宽。这类方法称为延迟光照、pre-lighting 或 light prepass。变体包括低分辨率 G/L-buffer 加双边上采样(光照变化剧烈时如反射表面上的粗糙度或法线贴图会有瑕疵)、对反照率用 Y'CbCr 子采样。局限是材质和光照模型可能受更多限制:转向基于物理的材质后需要存储镜面反射率以计算菲涅耳项,这促使一些团队从 light prepass 转向完整延迟着色。
何时选择
光源少、过度绘制少时延迟着色可能总体更慢;只有太阳一个光源时不需要光源剔除预处理。几何处理复杂或表面着色昂贵时,延迟着色能避免过度绘制、减少程序与状态切换等驱动开销,并允许用更少调用渲染更大的合并网格。同一帧里可以混用多种方法,最佳组合可能因物体或光源而异。光源很多时进一步使用 分块着色 与 分簇着色。
GEA 的视角:G-buffer 与光照预通道(卷 II 12.5.12.1、12.5.12.3)
- 前向渲染的低效(卷 II 12.5.12):先给三角形的顶点着色,到光栅化阶段才发现整个三角形被 z 测试剔掉;early-z 能消掉部分无用的像素着色但并不完美;要处理大量光源,还会冒出大量顶点和像素着色器版本(不同光源数目、光源类型、蒙皮权重数……)。
- G-buffer:先不管光照,高效渲染场景,把光照所需的信息存进"深"帧缓冲 G-buffer,再用它做光照与着色。GEA 认为这通常比在观察空间里做光照高效得多,避免了着色器变体膨胀,并且能比较容易地做出一些漂亮的效果。物理上它可以是一组缓冲,概念上是每像素一组丰富的属性:深度、观察空间或世界空间法线、漫反射色、高光指数,甚至 PRT 系数(卷 II 12.5.12.1)。
- GEA 以 Guerrilla Games《杀戮地带 2》为例,展示的 G-buffer 分量有反照率、深度、观察空间法线、屏幕空间二维运动向量(用于运动模糊)、高光指数和高光强度。
- 光照预通道 (light pre-pass) 分三阶段(卷 II 12.5.12.3):
- 画一遍几何,只往小得多的 G-buffer 里写少量信息(通常只有深度、法线、高光指数);
- 逐光源处理,结果存进屏外渲染目标;
- 再画一遍几何,用前向风格着色,从屏外渲染目标读光照。 优点是 G-buffer 小、带宽低,也更容易支持多种材质;缺点是要画两遍几何,顶点很重的场景可能吃不消。GEA 引用了 Insomniac 在 GDC 2009 的《抵抗 2》预光照演讲。
- 与本页的关系:本页「光照预通道与 L-buffer」描述的累加漫反射与镜面项到 L-buffer、最后乘纹理色的方案与 GEA 的三阶段描述是同一类思路;GEA 明确了"几何画两遍"的代价,RTR4 侧重带宽与纹理只读一次的好处。
LearnOpenGL 的视角:G-buffer MRT、光照体积与前向混合(Advanced Lighting / Deferred Shading)
来源:Deferred Shading;摘录 Advanced Lighting — Deferred Shading。
前向:每物体 × 每灯 × 多片元浪费。延迟:几何 pass 用 MRT 写入 G-buffer(位姿/法线常用 RGBA16F,albedo+specular 可打进一张 RGBA8)→ 光照 pass 全屏四边形按像素采 G-buffer,每像素只算一次可见片元光照。
局限:内存大、无传统混合、MSAA 难。做法:glBlitFramebuffer 拷几何深度到默认 FBO,再前向画需要混合/特殊着色的物体(如灯立方体)。
光体积:由衰减解半径(亮度阈约 5/256);shader 里 if(distance<radius) 在 GPU 上常无效(锁步执行)。正确做法:按半径缩放球体,延迟光照 shader 画球体(建议画背面),片元自然覆盖受影响像素,复杂度近 物体+灯。进阶:tile/cluster deferred。法线/视差可在几何 pass 输出世界法线或先偏移 UV。链 分块着色、分簇着色、UE5 渲染架构。
GPU Gems 的视角:Tabula Rasa 的生产级延迟管线(GPU Gems 3 第 19 章)
来源:Rusty Koonce《Deferred Shading in Tabula Rasa》;摘录 Chapter 19. Deferred Shading in Tabula Rasa — Rusty Koonce。接 Shishkovtsov《S.T.A.L.K.E.R.》一章之后的工程经验,与上文 LearnOpenGL/RTR/GEA 的 G-buffer 理论对照。
MMO 无法控制同屏人数与灯数,前向照明开销随几何×灯数恶化,故主路径改延迟(要求 SM3),前向仅作半透明与低配回退。材质与光照彻底拆开:加新灯型不必改材质着色器。实践中的灯型包括双向平行光(正/背色近似环境反射)、Globe Map(立方体/2D 给灯光染色或假阴影)、盒灯(局部平行光+衰减)。阴影全部动态阴影图(无 lightmap),静态/动态投射体分开;阴影图池化并按优先级分帧重建。
深度与法线缓冲的额外价值:水面按眼空间厚度做岸线与折射判定;用邻域深度梯度相对变化 + 法线夹角做分辨率无关的边缘权重,再与邻像素双线性混合冒充抗锯齿。带宽是第一瓶颈——分辨率几乎线性决定成本;漫反射/高光分两张累加 RT,材质属性用访问函数封装以免改 MRT 布局时改全体着色器。半透明仍只能前向,发丝与植被改 alpha test 进延迟以保证进阴影;植被淡入用缩放代替真正混合。稳定阴影需量化光源矩阵,避免亚像素抖动。
GPU Gems 的视角:S.T.A.L.K.E.R. 延迟着色奠基(GPU Gems 2 第 9 章)
来源:Oles Shishkovtsov《Deferred Shading in S.T.A.L.K.E.R.》;摘录 Chapter 9. Deferred Shading in S.T.A.L.K.E.R. — Oles Shishkovtsov。Gems3 Tabula Rasa 章的直接前传:全动态光照的生产级延迟引擎。
动机不只是「灯光与几何解耦」,更是砍掉动态阴影带来的 CPU batch,并避免前向里每个灯重复跑一遍昂贵材质。破除迷思:在中等过度绘制下延迟并不更慢;带阴影的平行光(太阳)仍可用模板跳过天空、背光与 AO=0 像素,实测约 2×。材质不是改光着色器排列组合,而是 G-buffer 写 material ID,灯着色器查表——等于把前向「灯改材质」倒过来。
G-buffer 选型宁可选解码简单的胖格式(眼空间位置+AO、法线+材质用 A16R16G16B16F),也不要为省带宽选难解的打包。全向阴影当六盏聚光灯更利于过滤与打包。虚拟位置(沿法线按高度微移)改善视差与阴影粉刺。边缘检测 AA、Bloom 曝光、半透明仍走无影前向。与 延迟着色 上文 Tabula Rasa 对照:STALKER 更偏 DX9 极限优化与材质 LUT;TR 更偏灯型扩展与分辨率无关边权。
出处
- realtime_rendering_4ed.pdf 第 20 章 Efficient Shading
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 12 章 12.5.12.1、12.5.12.3 节
- Chapter 19. Deferred Shading in Tabula Rasa — Rusty Koonce
- developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-19-deferred-shading-tabula-rasa
- Chapter 9. Deferred Shading in S.T.A.L.K.E.R. — Oles Shishkovtsov
- developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-9-deferred-shading-stalker
- Advanced Lighting — Deferred Shading
- learnopengl.com/Advanced-Lighting/Deferred-Shading