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 应跟着目标物体移动。
1. 从镜头模型得到 CoC
↡离焦点在成像面上形成的模糊圆直径,用于把物体相对焦平面的距离转换为像素 blur 半径(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 与伪影。
↡用多个相机采样并把结果累积到高精度颜色缓冲的景深方法,用更多场景 pass 逼近真实镜头 通过从不同镜头位置渲染多次,再混合结果近似 distributed ray tracing。CoC 面积越大,需要的 pass 越多;样本不足会在远近景出现 ghosting 或 banding,整数缓冲的精度也可能不足。它适合质量优先、可以接受非实时成本的路径。
↡将场景按深度切成互不重叠层、对每层使用代表性 blur 后再合成的景深方法 只在场景可以可靠分层时简单有效。每层独立保存可见物体,因此边缘 visibility 比直接 blur 一张全屏颜色图更可控;但一个物体跨越很大深度范围时,整层统一 blur 会出现内部不自然的焦散边界,层与层之间也可能藏入错误的遮挡。
3. z-buffer 后处理:从 CoC 到可变模糊
↡把源像素按 CoC 直径作为 sprite 投到目标图像,并用 alpha 权重近似离焦圆的 forward-mapped 景深方法 保存 color 与 depth,按每个源像素的 CoC 将颜色作为圆形 sprite 写回 frame buffer。为了减少前景模糊污染前景清晰物体,源像素只混合到比自己更远的邻域,最终还需要按 alpha 总和重新归一化。它适用于任意场景,但大量 sprite 和每像素最大 CoC 会迅速消耗预算。
↡按每个像素 z 值选择不同模糊等级或纹理 mip,再把结果合成为景深的后处理方法 反过来让每个目标像素根据自己的 CoC 读取模糊图像。最简单的版本用 scene texture 的 mipmap;更高质量的版本预先生成多个 blur level,或用 summed-area table 查询更大范围。这个方法通常最快,却最容易在深度断点、bilinear magnification 和颜色 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. 伪影诊断:先定位证据缺口
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 会变小?
观察: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.6、cocScale=0.8、cocBias=-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 选择模糊纹理等级的后处理景深方法。