对象空间与纹理空间着色
Object- & Texture-Space Shading
对象空间/纹理空间着色把着色计算的频率与几何采样(光栅化)的频率解耦:在物体的参数化(纹理图表)上计算着色并存入纹理,最终光栅化时只查表。思想源自 Pixar 的 Reyes 离线渲染器的微多边形着色。它能消除 quad 过度着色、按屏幕覆盖率控制着色量、在帧间复用着色结果,甚至让着色以低于光栅化的帧率异步运行;代价是物体必须有唯一的 uv 图表、先着色后遮挡带来浪费等。
Reyes 的启发(20.6 节)
Reyes(名字来自 Point Reyes 半岛,也被解释为 "Renders Everything You Ever Saw")把每个表面切分 (dice) 成极细的四边形网格——微多边形,按视点切分到每个约半个像素宽高,以满足奈奎斯特极限;视锥外或背向的四边形被剔除。原始系统给每个微多边形着一个颜色(后来演进为对微多边形网格顶点着色)。微多边形插入每像素抖动的 4×4 采样网格(超采样 z-buffer),抖动把走样变成噪声。着色发生在按覆盖率光栅化之前,因此叫基于对象的着色;相比之下前向着色在光栅化时于屏幕空间着色,延迟着色在光栅化之后着色。
| 优点 | 缺点 |
|---|---|
| 材质纹理与微多边形直接对应,可切分到每个微多边形含 2 的幂个纹素,取到精确过滤的 mipmap 样本;按顺序访问微多边形使纹理访问缓存一致(环境反射贴图等仍需常规采样过滤) | 所有物体必须能细分且切得很细 |
| 运动模糊:每个微多边形在帧间隔内的抖动时刻放到其路径上的位置;景深类似地按弥散圆分布 | 着色在 z-buffer 遮挡测试之前,过度绘制会浪费着色 |
| 按奈奎斯特采样不代表能捕捉锐利高光等高频现象,只足以重建较低频率 |
一般而言每个物体必须"可制图表",即顶点 (u, v) 让模型每块不同区域对应唯一纹素。基于对象的着色可以看作先烘焙着色,再用相机决定视相关效果并限制每块表面花费的工作量。在 GPU 上最简单的做法是细分到亚像素再逐顶点着色,但很贵:三角形设置开销无法摊到多个像素上,而且单像素三角形因 quad 渲染会产生 4 次像素着色调用;GPU 是为覆盖较多像素(如 16 个以上)的三角形优化的。
研究路线
- Burns 等:先确定可见的物体位置——对物体切分出"多边形网格"、尽量剔除后光栅化;再用独立的对象空间"着色网格"只给可见区域着色,每个纹素对应一块表面,分辨率可与多边形网格不同。他们发现非常细的几何细分收益很小,解耦后资源利用更高效(仅在模拟器中实现,但影响了后续研究)。
- 解耦采样:Ragan-Kelley 等提出硬件扩展,样本有五维(两维亚像素、两维镜头、一维时间),可见性与着色分别采样,用"解耦映射"决定可见性样本对应的着色样本,用于运动模糊和景深。Liktor 与 Dachsbacher 在随机光栅化中缓存并复用着色样本——这些效果不需要高着色率。
- 纹理空间着色硬件扩展(Clarberg 等):消除 quad 过度着色,从而允许更小的三角形;像素着色器从着色纹理查值时可用双线性或更复杂的过滤,降低纹理分辨率即可降低着色开销,对低频项通常效果很好。
- Andersson 等的纹理空间着色:每个三角形先做视锥和背面剔除,再按其 (u, v) 参数化着色到输出目标的对应区域;同时用几何着色器计算三角形在相机中的大小,决定插入类 mipmap 结构的哪一级,使着色量与屏幕覆盖率相关;最终用随机光栅化查着色纹理,着色值可复用于运动模糊和景深。
- Hillesland 与 Yang:先把几何画到最终视图并存三角形 ID 可见性缓冲,计算着色器填充类 mipmap 的对象着色结构,再画一遍几何查表。由于着色在对象空间,同一区域每帧对应同一纹理位置,若某 mip 级的着色已算过且不太旧就复用:在 60 FPS 下隔帧复用误差可忽略。mip 级不仅可按屏幕大小选,也可按法线变化等因素选;更高的 mip 级意味着每个屏幕片元计算的着色更少,可大幅节省。
《奇点灰烬》的实现
Oxide Games 的渲染器受 Reyes 启发,对每个模型整体做纹理空间着色,一个物体可有任意多种材质,用遮罩区分:
flowchart TD A["分配若干 4k x 4k, 每通道 16 位的主纹理"] --> B["评估所有物体, 可见则估算屏幕面积"] B --> C["按面积给每个物体分配主纹理区域, 总量超出时按比例缩小"] C --> D["计算着色器逐材质做纹理空间着色并累加到主纹理"] D --> E["按需生成主纹理 mipmap"] E --> F["光栅化物体, 用主纹理着色"]
- 一个地形模型可包含泥土、道路、植被、水、雪、冰,各有自己的 BRDF。
- 着色时掌握物体表面与主纹理的完整关系,可在像素和着色器两个层面抗锯齿,能稳定处理镜面指数极高的模型。
- 着色结果附着在整个物体上、与可见性无关,所以着色可以用不同于光栅化的帧率:着色 30 FPS、光栅化 60 FPS(VR 为 90 FPS)即可;着色负载过高时几何帧率仍能保持。场景由约一千个光源照亮(每辆车、每颗子弹至少一个)。
挑战:
- 批次约为典型引擎的两倍(每个物体的"材质四边形"在计算着色器中处理一次、光栅化时再画一次),但多数批次简单,DirectX 12 / Vulkan 能降低开销。
- 主纹理分配方式显著影响画质;屏幕上很大或纹素密度变化大的物体(如地形)有问题,需要额外缝合不同分辨率的地形瓦片。
- AO 等屏幕空间技术难以实现。
- 与原始可见性缓冲一样,影响形状的动画要做两次(着色与光栅化各一次)。
- 先着色后遮挡造成浪费;对深度复杂度低的即时战略游戏代价较低。每种材质评估简单,不像复杂的延迟着色器。
- 粒子、树木这类着色简单的物体获益很少,可改用前向着色。
出处
- realtime_rendering_4ed.pdf 第 20 章 Efficient Shading