【Virtual Globe 渲染技术笔记】9 深度缓冲精度

深度缓冲精度

每个图形开发者迟早会问:“近平面和远平面到底该设多远?”
更激进的会问:“我把近平面设成 0.0001、远平面设成一个天文单位不行吗?”
当他们第一次看到由此产生的 z-fighting(深度冲突)时,那震惊的表情——无价!


9.1 深度缓冲出错的根源

9.1.1 透视投影的非线性
  • 正交投影:zeye 与 zwindow 呈线性关系,精度均匀。
  • 透视投影:zeye 与 zwindow 呈 1/zeye 关系,近处精度极高,远处精度骤降。

推导过程(OpenGL 透视矩阵)
设近平面 n、远平面 f,则
zndc=f+nf−n+2fnzeye(f−n) z_{\text{ndc}} = \frac{f+n}{f-n} + \frac{2fn}{z_{\text{eye}}(f-n)} zndc=fnf+n+zeye(fn)2fn
再经视口变换(nrange=0, frange=1):
zwindow=zndc+12=12(f+nf−n+2fnzeye(f−n)) z_{\text{window}} = \frac{z_{\text{ndc}}+1}{2} = \frac12\left(\frac{f+n}{f-n} + \frac{2fn}{z_{\text{eye}}(f-n)}\right) zwindow=2zndc+1=21(fnf+n+zeye(fn)2fn)
因此
zwindow∝1zeye z_{\text{window}} \propto \frac1{z_{\text{eye}}} zwindowzeye1
f/n 很大,远处 zwindow 的离散值极少 → z-fighting(图 6.1(a))。

最小可分辨距离(Baker 近似,x-bit 定点深度缓冲):
Smin⁡(zeye)≈zeye22xn−zeye S_{\min}(z_{\text{eye}})\approx \frac{z_{\text{eye}}^2}{2^x n - z_{\text{eye}}} Smin(zeye)2xnzeyezeye2
越远 Smin 越大,越难区分两张紧挨的片元。


9.2 基本对策

  1. 把近平面推远(最有效)

    • 每把 n 推远 1 m,效果 ≈ 把 f 拉近 500 m(当 nf)。
    • 可用雾或淡出避免近裁剪突兀。
  2. 把远平面拉近

    • 次优,但可配合雾/淡出隐藏远处物体。
  3. 动态调整 n/f

    • 根据相机高度实时更新,保证 f/n ≤ 1000(经验值)。
  4. 剔除/淡出远处对象

    • 既减少 f,又清理画面。

9.3 互补深度缓冲(Complementary Depth Buffer)

  • 思路:翻转深度映射,使浮点精度最高的 0 值用在最远片元。
    • 清除深度值为 0(而非 1);
    • 深度比较改为 GL_GREATER
    • 构造透视矩阵时互换 nf
  • 结果:远平面获得浮点最高精度,近平面精度下降,整体更均衡。
  • 24 位定点缓冲也有一定收益。图 6.7 展示了对比效果。

9.4 对数深度缓冲(Logarithmic Depth Buffer)

在顶点/片元着色器中把 zclip 替换为
zclip′=2ln⁡(C zclip+1)ln⁡(C f+1)−1 z_{\text{clip}}' = 2\frac{\ln(C\,z_{\text{clip}}+1)}{\ln(C\,f+1)} - 1 zclip=2ln(Cf+1)ln(Czclip+1)1

  • C 越小 → 远处精度越高,近处精度越低。
  • 推荐在片元着色器写入 gl_FragDepth,避免顶点插值带来的误差。
  • 图 6.8-6.9 展示了不同 C 的效果。

9.5 多视锥体渲染(Multifrustum Rendering / Depth Partitioning)

把超大视距切成 多个视锥体(depth partition),每个 f/n ≤ 1000:

视锥体nearfar
11 m1 000 m
21 000 m1 000 000 m
31 000 000 m100 000 000 m
  • 渲染顺序:先远后近,每段清空深度缓冲。
  • 重叠少许(如 1%)防止裂缝。
  • 优点
    • 兼容老显卡,理论视距无限。
    • 极少需要雾/淡出。
  • 缺点
    • 同一物体可能跨多个视锥体,需渲染多次 → CPU/带宽/片段开销增加。
    • 半透明重叠区域会出现颜色带(图 6.11)。
    • 对延迟渲染、early-z 优化不友好。

STK 实践:默认 1 m / 100 Mm,f/n = 1000,通常 3-4 个视锥体即可。


9.6 W-Buffer(已废弃)

  • 原理:使用线性 wclip(即 zeye)作为深度值,分布均匀。
  • 问题w 在窗口空间非线性,插值昂贵,硬件不再支持。

9.7 方案对照表(表 6.2)

技术要点适用场景
调整近平面/远平面简单、快速;推远 n 最有效所有场景起点
剔除/淡出远处物体降低 f,同时清理画面高空视角、LOD
互补深度缓冲翻转深度映射,浮点精度最大化支持浮点深度的硬件
对数深度缓冲顶点/片元着色器改 z,远距精度高单视锥体、长视距
多视锥体渲染分区视距,兼容老显卡虚拟地球、太空场景
W-Buffer已淘汰,不再讨论

组合使用

  • 先推远 n、拉近 f
  • 若仍不足,再叠加对数深度或多视锥体;
  • 互补深度缓冲可与多视锥体并用,减少分区数量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值