GPU Gems 1 · Chapter 23. Depth of Field: A Survey of Techniques

从镜头模型与 circle of confusion 出发,对比 ray tracing、accumulation buffer、layered、forward z-buffer 与 reverse z-buffer 景深,并拆解实时后处理的伪影。

学习目标

  • 能用镜头、焦平面和 circle of confusion 解释景深,而不是把景深误解为全屏 blur
  • 能比较五类 depth of field 技术的 visibility、质量、速度和伪影取舍
  • 能从 z-buffer 计算每像素 CoC,设计 mip 或纹理后处理,并指出 depth discontinuity、bilinear 与 pixel bleeding 风险
  • 能根据实时预算选择算法和回归样本,验证焦点、光圈、运动和后处理稳定性

摄影中的景深让一段距离范围内的物体保持清晰,焦平面前后的物体则逐渐失焦。传统实时渲染使用理想 pinhole camera,镜头尺寸为零,每个像素只有一条光线路径,因此不会自然产生真实镜头的离焦圆。GPU 实现需要从颜色和深度证据中近似这种效果。

的关键不是“模糊越多越好”,而是模糊半径随物体与 focus plane 的距离变化。光圈越大,离焦区域的影响越明显;焦平面移动时,最小 CoC 应跟着目标物体移动。

depth of field:焦平面内清晰,焦平面外形成 CoCcameralens aperturefocus planeforegroundmidgroundbackgroundlarge CoCsmall CoClarge CoCCoC diameter grows with aperture and distance from focus
景深不是全屏统一模糊:每个物体相对 focus plane 的距离决定 CoC 大小,光圈越大,离焦区域越明显。

1. 从镜头模型得到 CoC

(CoC)是实时景深的桥梁。若 objectDistance 是相机到物体的距离,planeInFocus 是焦平面距离,aperture 是光圈参数,官方章节给出的近似关系可以写成:

float coc = abs(
  aperture * (focalLength * (objectDistance - planeInFocus)) /
  (objectDistance * (planeInFocus - focalLength))
);

工程上常把相机参数折叠成 scale 与 bias,直接从 z-buffer 得到:

float coc = abs(z * cocScale + cocBias);

这一步隐含了深度表示契约。z-buffer 可能是非线性的,near/far plane、projection matrix 和世界空间距离不能混用;如果焦点在很远处,浮点精度和深度不连续会直接影响 CoC。先用一条从近到远的深度 ramp 检查 CoC 曲线,再把它连接到颜色后处理。

2. 五类技术如何交换质量与速度

官方章节综述了五条路线:跨镜头表面分布 ray tracing、多相机 accumulation buffer、按深度分层、forward-mapped z-buffer,以及 reverse-mapped z-buffer。前两类更接近真实镜头但代价高;z-buffer 技术更适合当前 GPU 的实时后处理,因此工程讨论应集中在它们的 visibility 与伪影。

technique survey:质量、速度与伪影的三角取舍techniquequalityspeedmain concernray tracedcorrect shading, noiseaccumulationmany scene passeslayeredsorted scenes onlyforward z-buffersprites / bleedingreverse z-bufferfast, depth edgesz-buffer techniques deserve the most real-time engineering attention
官方章节的结论不是选出唯一算法,而是按目标取舍:正确 shading 偏向 ray tracing,实时速度偏向 z-buffer,后处理质量可考虑 splatting。

通过从不同镜头位置渲染多次,再混合结果近似 distributed ray tracing。CoC 面积越大,需要的 pass 越多;样本不足会在远近景出现 ghosting 或 banding,整数缓冲的精度也可能不足。它适合质量优先、可以接受非实时成本的路径。

只在场景可以可靠分层时简单有效。每层独立保存可见物体,因此边缘 visibility 比直接 blur 一张全屏颜色图更可控;但一个物体跨越很大深度范围时,整层统一 blur 会出现内部不自然的焦散边界,层与层之间也可能藏入错误的遮挡。

3. z-buffer 后处理:从 CoC 到可变模糊

保存 color 与 depth,按每个源像素的 CoC 将颜色作为圆形 sprite 写回 frame buffer。为了减少前景模糊污染前景清晰物体,源像素只混合到比自己更远的邻域,最终还需要按 alpha 总和重新归一化。它适用于任意场景,但大量 sprite 和每像素最大 CoC 会迅速消耗预算。

反过来让每个目标像素根据自己的 CoC 读取模糊图像。最简单的版本用 scene texture 的 mipmap;更高质量的版本预先生成多个 blur level,或用 summed-area table 查询更大范围。这个方法通常最快,却最容易在深度断点、bilinear magnification 和颜色 bleeding 处暴露近似限制。

reverse-mapped z-buffer:z → CoC → variable blurcolor + depthpinhole renderCoCfocus / apertureblur sourcemip / textureper-pixelz chooses radiusselect radiuscompositenormalize alphaquality knob: mip filter, jitter, extra samples, layer separation
反向 z-buffer 把每个像素的 z 值变成 CoC,再选择 mip 或预模糊纹理;速度高,但深度不连续和颜色 bleeding 需要单独处理。
float coc = abs(z * cocScale + cocBias);
float lod = saturate(coc * maxBlurMip);
float3 blurred = tex2Dlod(sceneColor, float4(uv, 0.0, lod)).rgb;
return float4(blurred, 1.0);

不要把这段伪代码当成完整发布 shader:真实实现要决定 mip 生成过滤、CoC 到 lod 的标定、前后景合成和 alpha 归一化。硬件自动生成 mipmap 通常更快,但三乘三或五乘五的 downsample 可以减少低级纹理的方块感;质量和带宽必须在目标 GPU 上测量。

4. 伪影诊断:先定位证据缺口

artifact map:CoC 选择正确不代表 visibility 自动正确depth edgeforeground blur crosses sharp objectbilinearmip magnification shows blockspixel bleedfar color leaks into focusmitigate with extra depth evidence, better filters, jitter, or per-object layers
三个伪影共享一个根因:后处理只看到有限的颜色与深度证据。修复不是盲目扩大 blur,而是补充 depth samples、过滤、jitter 或 layer mask。

depth discontinuity 是最难看的问题之一:一个 z 值不足以说明前景模糊应该怎样覆盖中景。读取多个深度样本可以提供更多证据,但固定数量样本可能只产生一个半径固定、逐渐衰减的 halo;直接 blur depth 又会把锐利边缘模糊掉。实际产品往往通过额外 blur bias、限制焦平面位置、层分离或艺术遮罩规避最坏情况。

bilinear interpolation artifact 来自放大较小的 mip 或 blur texture。可以用 summed-area table、多个全尺寸 blur、按 CoC 抖动采样,或接受由 jitter 引入的细噪声来换取不出现爬行的方块图案。pixel bleeding 则是颜色图被无差别模糊:焦点内的颜色会错误渗到离焦区域,分对象渲染与分别合成只能缓解常见场景,不能成为通用可见性证明。

5. 动手实验:把摄影控制变成 GPU 参数

先预测四个变化:focus plane 接近某个物体时,该物体的 CoC 应下降;aperture 增大会扩大前景和背景 CoC;filter quality 降低可能出现 banding、jitter 或 pixel bleeding;depth edge 增大时,reverse z-buffer 的 artifact 指标应上升。

Depth of Field Lab

先预测:焦平面移动时,哪一个物体的 CoC 会变小?

可交互
depth line / CoC previewreverse z-bufferfocusforegroundCoC 0.37midgroundCoC 0.00backgroundCoC 0.37cost 0.55artifact 0.44depth edge is relatively stable · more samples or jitter may help

观察:aperture 放大离焦 CoC;quality 降低成本可能带来 banding、jitter 或 pixel bleeding;算法选择决定真实 visibility 与实时预算。

实验采用确定性的三层场景,目的是建立参数因果,而不是替代真实镜头渲染。发布前要在前景遮挡细线、焦平面远近切换、相机运动、透明物体、最大 CoC、mip 边界和不同分辨率下回归;同时记录每个算法的 pass 数、纹理带宽、最大半径和可接受伪影。

小结:景深是相机模型与可见性近似的协商

  • depth of field 由 focus plane 和 aperture 共同决定,CoC 把镜头距离转成每像素的 blur 规模。
  • ray tracing 与 accumulation buffer 更接近真实 visibility,但可能不可实时;layered 方法简单却依赖场景可分层。
  • forward-mapped z-buffer 以 sprite 传播源像素,reverse-mapped z-buffer 以 z 选择模糊纹理;后者通常更适合实时后处理。
  • depth discontinuity、bilinear interpolation 和 pixel bleeding 是证据不足的表现,应通过深度样本、过滤、jitter、layer mask 或场景约束处理。
  • 没有单一算法满足所有质量与速度要求,发布选择必须和最大 CoC、样本预算及回归场景一起记录。

练习

问题 1|推导题 某像素的 z=0.6cocScale=0.8cocBias=-0.2。计算 abs(z × cocScale + cocBias);如果焦平面移动使 bias 变成 -0.5,该像素的 blur 趋势是什么?

问题 2|方法选择题 一个镜头场景需要真实 visibility,但允许离线渲染;另一个游戏后处理场景要求稳定实时帧率。分别优先选择哪类技术?写出一个主要风险。

问题 3|独立实现题 为第三人称游戏设计一个 reverse z-buffer 景深 pass。请列出输入、关键计算、至少三条伪影防线和回归样本。

名词解释

本章出现的专业名词,用大白话再讲一遍。

depth of field
让焦平面内一段距离范围清晰、焦平面前后逐渐失焦的镜头成像效果。
circle of confusion
离焦点在成像面上形成的模糊圆直径,用于决定 blur 半径。
accumulation buffer
累积多个镜头采样结果的高精度颜色缓冲,用更多场景 pass 逼近真实景深。
layered depth of field
按深度切分场景层、分别模糊并合成的景深方法。
forward-mapped z-buffer
以 CoC 为 sprite 直径把源像素传播到目标图像的 z-buffer 景深方法。
reverse-mapped z-buffer
按每个目标像素的 z 与 CoC 选择模糊纹理等级的后处理景深方法。

资料与写作方式声明

本章以GPU Gems 系列权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…