中EN
概念页

分块着色

Tiled Shading

分块着色把屏幕划分为瓦片(如 32×32 像素),先为每个瓦片建立可能影响它的光源列表,着色时每个像素在一次着色器调用中只遍历所在瓦片的列表。它可用于延迟着色(tiled deferred),也可用于前向着色(tiled forward,又称 Forward+)。配合 z-prepass 得到的瓦片深度范围可进一步剔除光源,但深度不连续会削弱效果,于是出现 HalfZ、2.5D 剔除等改进。

动机(20.3 节)

基础延迟着色对每个光源单独调用着色器并重复读 G-buffer,数百上千个光源时很昂贵;在一次调用中评估多个光源更高效。早期探索有 Zioma(渲染光源体积,逐像素存光源信息,用深度剥离处理重叠,受限于每像素重叠光源数)和 Trebilco(z-prepass 后渲染光源体积,逐像素存光源 ID,用位移与混合技巧不用多次剥离就能存 4 个光源)。分块着色由 Balestra 与 Engstad 于 2008 年在《神秘海域:德雷克船长的宝藏》中首次提出,随后用于 Frostbite、PhyreEngine 等。

这里的瓦片是开发者选择的结构,与移动 GPU 的分块渲染或硬件内部瓦片关系不大。对光源体积做分块"渲染"相当于对场景做低分辨率渲染,可在 CPU 或 GPU 计算着色器中完成。

光源与瓦片的相交测试

瓦片的屏幕边界构成一个不对称视锥,用它测试每个光源的球形影响范围。按瓦片而非逐像素存储是保守的(光源未必覆盖整个瓦片),换来大幅降低的处理、存储与带宽。

常规的球-视锥测试假设视锥宽大、球较小;瓦片视锥细长且不对称,会产生大量假阳性(球同时与底面和右侧平面相交而被误报)。改进是在平面测试后再加一个球-盒测试(盒包围视锥),两者交集显著减少误报。聚光灯用球包围效果不好,可用层次剔除、光栅化和代理几何优化。

Tiled deferred 的好处

  • 每个像素的 G-buffer 总共最多读一次,而不是每个光源一次。
  • 输出图像只写一次,不用逐光源累加。
  • 着色器可把渲染方程的公共项提出来只算一次。
  • 瓦片内所有片元遍历同一列表,warp 执行一致。
  • 不透明物体完成后,透明物体可用同样的光源列表做前向着色。
  • 所有光源在一遍中计算,帧缓冲精度可以低(传统逐光源累加在 8 位通道上会产生色带);不过现代系统为色调映射通常需要高精度输出,这点意义不大。

Tiled forward / Forward+

先做几何 z-prepass(避免最终 pass 过度绘制并支持深度剔除),计算着色器按瓦片分类光源,再做第二遍几何前向着色,按片元屏幕位置取光源列表。《教团:1886》使用了它。Pettineo 的开源测试中:无抗锯齿时随光源数增至 1024,延迟在许多 GPU 上占优;抗锯齿级别提高时前向更好。

深度范围剔除

对每个瓦片用归约操作求不透明物体的 zminz_{min} 与 zmaxz_{max}(例如 Harada 等用计算着色器和 UAV 同时做视锥剔除与归约),剔除不与该范围重叠的光源;只看到天空的空瓦片可直接跳过。是否使用最小、最大或两者取决于场景。延迟着色的 G-buffer 中已有深度,同样可用。

flowchart LR
  A["z-prepass 或 G-buffer 深度"] --> B["每瓦片归约 zmin, zmax"]
  B --> C["瓦片视锥 + 深度范围 测试每个光源"]
  C --> D["生成瓦片光源列表"]
  D --> E["着色: 遍历本瓦片列表"]

透明物体:深度范围来自不透明表面,透明需单独处理。Neubelt 与 Pettineo 在不透明 z-prepass 缓冲上再渲染透明表面,取透明表面的 zminz_{min}、以不透明的 zmaxz_{max} 封住远端,另做一次光源分类生成新列表,再只让透明表面走类似 tiled forward 的渲染。

深度不连续问题:一个瓦片里近处角色背后是远山,zz 范围巨大,几乎无法剔除光源。这种瓦片在场景中占比可能很高,森林、高草、植被场景更甚。

  • HalfZ / 双峰簇:在 zminz_{min} 与 zmaxz_{max} 中点分一次,把相交光源归为近半、远半或全范围。直接解决"一近一远"两物体的情形,但不能解决光源两者都不碰或多于两个深度层的情况。
  • 2.5D 剔除(Harada 等):把深度范围沿深度方向分成 nn 个单元(他们用 n=32n=32),按像素深度生成 nn 位几何掩码,再为每个与瓦片视锥相交的光源生成光源掩码,两者按位与为 0 则该光源不影响瓦片内任何几何。
  • 在某款 GPU 上(Stewart 与 Thomas),光源超过 512 个后 HalfZ 开始胜过基础 tiled deferred,超过 2300 个后 2.5D 剔除占优,但优势不大。
  • 逐像素裁剪(Mikkelsen):16×16 瓦片先用光源屏幕包围矩形和几何深度范围剔除,再让 64 个计算线程每个检查 4 个像素的世界位置是否在光源体积内,没有任何像素在内就剔除——只保留保证至少影响一个像素的光源。他发现对其场景再做 z 轴剔除反而降低总体性能。

按瓦片特化着色器

光源合并成列表后,单个延迟着色器要处理所有材质和光源类型,会很复杂。可在每个像素存一个特性位掩码(每位代表材质在该像素使用的一项着色特性),瓦片内按位或得到所需的最小特性集合,按位与得到所有像素都用到的特性(无需 if 判断),选用对应的特化着色器。这不仅减少指令,还因为不必为最坏路径分配寄存器而提高占用率。也可跟踪其他属性,例如《Split/Second》按 4×4 瓦片分类是否完全或部分处于阴影、是否含需要抗锯齿的多边形边等。

GEA 的视角:Forward+(卷 II 12.5.12.4)

  • 前向渲染把光源列表交给管线,每个光源用球或锥体限定影响范围;但每个片元仍要遍历全部光源才能知道哪些影响它。先剔除与视锥不相交的光源能改善一些,但列表仍可能很长(卷 II 12.5.12.4)。
  • Forward+ 把屏幕划分成规则网格,预先测试每个格子受哪些光源影响,结果存进与网格同尺寸的二维缓冲;前向着色时像素着色器找到片元所在格子,只遍历该格的光源。GEA 认为这让"几乎不限数量的光源"也能高效渲染。
  • 术语分歧(原书问题,12.5.12.4):GEA 说 Forward+ "也叫分块渲染 (tiled rendering) 或分簇前向渲染 (clustered forward rendering)",而它描述的是只在屏幕上二维划分的网格。RTR4(本页与 分簇着色)把二者区分开:分块着色只划分屏幕瓦片(可加深度范围剔除),分簇着色还沿深度方向切分成三维簇。按 GEA 自己的描述,它讲的是分块前向;"分簇"另有所指。另外 "tiled rendering" 一词也常指移动 GPU 的分块渲染架构,与这里的光源分块是不同概念(见 分簇着色 的「移动端」)。出处:Forward+ 即分块前向,Harada, McKee, Yang, "Forward+: Bringing Deferred Lighting to the Next Level", Eurographics 2012 短文;分簇着色是 Olsson, Billeter, Assarsson, "Clustered Deferred and Forward Shading", HPG 2012 提出的另一种方法。
  1. realtime_rendering_4ed.pdf 第 20 章 Efficient Shading
  2. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  3. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 12 章 12.5.12.4 节

相关页面

图形学延迟着色Deferred Shading延迟着色先用一遍几何 pass 把所有可见表面的材质参数写入多张渲染目标(G-buffer),再以后处理方式对这些存储值逐光源计算光照,从而把"几何可见性"与"光照"彻底解耦,并把材质与光源分离。它避免了着色的过度绘制、简化了着色器管理、天然适合贴花,但 G-buffer 占用显存和带宽,且难以直接支持透明和 MSAA。本页也覆盖前向渲染下限制光源影响范围的基础手段与"光照预通道 (light prepass)"类混合方案。图形学分簇着色Clustered Shading分簇着色把整个视锥(而不只是屏幕平面)划分为三维单元——簇 (cluster),按簇建立光源列表。与依赖场景几何深度的分块着色不同,簇的划分与几何无关,可只由视图和光源计算,因此对相机位置的性能波动更小、对深度不连续更稳健,并为不透明、透明、体积物体提供统一的光照方案。它同样可配合前向或延迟着色,并衍生出 z-binning、光源树等更省内存的变体。本页还汇总了各类多光源方案的对比。图形学计算着色器Compute Shader计算着色器是 DirectX 11 引入的一种 GPU 计算方式:它不固定在图形管线的某个位置,但由图形 API 调用,和其他着色器共用统一着色器核心。它暴露了线程组和组内共享内存,最大的优势是能直接处理 GPU 上生成的数据,不用来回传给 CPU。图形学GPU 并行架构GPU Parallel ArchitectureGPU 为吞吐量而设计:芯片大部分面积是成千上万个着色器核心,而不是缓存和控制逻辑。它靠在大量线程组 (warp/wavefront) 之间快速切换来隐藏访存延迟,用 SIMD 让一组线程锁步执行同一条指令。理解占用率和线程分歧,是写出高效着色器的关键。图形学像素与帧缓冲优化Pixel & Framebuffer Optimization需要着色的像素通常远多于顶点,所以像素处理优化往往最划算。核心手段:保证占用率以隐藏纹理延迟、按距离切换着色器 LOD、利用 early-z 并通过从前往后排序或 z-prepass 减少过度绘制、缩小帧缓冲每像素存储(色度子采样、YCoCg 棋盘),以及只在需要时开启混合、避免 GPU 回读。几何与光栅化阶段的常用优化也一并列出。图形学着色频率与材质系统Shading Frequency & Material Systems实现着色时要按"计算频率"划分工作:整个 draw call 不变的放到应用端作为 uniform,其余放在相应的可编程阶段。实践中大多数着色在像素级完成,顶点着色器负责变换和变形。材质系统把面向美术的材质与底层着色器组织起来,处理海量着色器变体的组合问题。图形学剔除技术Culling Techniques剔除 (culling) 是在渲染前尽快去掉对最终图像没有贡献的部分。本页讲几何类剔除:背面剔除(含成簇背面剔除与法线锥)、视锥剔除(层次化、平面掩码)、室内场景的入口剔除,以及牺牲质量换速度的细节剔除和小三角形剔除。更复杂的遮挡剔除见 遮挡剔除。游戏数学视锥相交测试View Frustum Intersection Tests层次视锥剔除遍历 BVH 时最频繁调用的就是视锥与包围体的测试,理想结果分三态:完全在外(剪掉子树)、完全在内(子树免测)、相交(递归)。本页讲从组合矩阵直接提取六个视锥平面、把"BV 对视锥"转化为"点对扩张/收缩体积"的推导思路,以及视锥-球、视锥-盒的高效保守测试及其误报情况。游戏开发 · UE5UE5 渲染架构UE5 Rendering ArchitectureUE5 的渲染器是独立的 Renderer 模块,在渲染线程 (Rendering Thread) 上以「场景代理」镜像游戏线程的组件状态,每帧按固定顺序执行深度预通道、G-buffer 基础通道、光照、雾、半透明和后处理。现代渲染代码用渲染依赖图 (Render Dependency Graph, RDG) 声明通道与资源,由 RDG 自动排屏障、复用瞬态内存、并行录制;最终命令经 RHI 线程翻译成 D3D12/Vulkan 等图形 API 调用。默认走延迟着色 (Deferred Shading),也可切换前向着色 (Forward Shading)。图形学像素着色器Pixel Shader像素着色器(OpenGL 里叫片元着色器)对光栅化产生的每个片元运行,用插值后的顶点数据算出颜色,也可以输出不透明度、修改深度或直接丢弃片元。多渲染目标让它一次输出多组数据,催生了延迟着色。它通常只能写自己所在的像素,但能通过 2×2 quad 拿到相邻像素的导数。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原