Wiki
740 words
4 minutes
深度缓冲

什么是深度缓冲?#

深度缓冲(Depth Buffer),又称 Z-Buffer,是 GPU 在渲染时维护的一张与屏幕等分辨率的缓冲区。它存储了当前已渲染的每个像素的深度值(通常为 0~1 的浮点数,代表距离摄像机的远近)。

当新的片元(像素)被光栅化时,GPU 会进行深度测试:比较新片元的深度值与缓冲区中已有的深度值,只有更近的片元才会被绘制并更新缓冲区。这个算法称为 Z-Buffer 算法

深度值的空间#

深度缓冲中存储的深度值处于 NDC(归一化设备坐标)空间,范围为 [0, 1](DirectX)或 [-1, 1](OpenGL),这是一个非线性的值——靠近摄像机的精度高,远处精度低。

若需要将深度值转换为线性的视角空间(View Space)距离,需要使用逆矩阵进行变换,这在运动模糊等后处理效果中会用到:

// 从深度图重建世界空间/视角空间位置的基本思路
// depth = 深度图采样值(NDC 空间)
// 需要 NDC → 视角空间的逆投影矩阵

与透明渲染的关系#

深度缓冲对不透明物体非常有效,无论渲染顺序如何,最终结果都正确。

但对于透明物体,情况不同:

  • 透明度混合需要将当前片元颜色与缓冲区颜色叠加,要求从后往前渲染
  • 因此透明物体通常需要关闭深度写入(ZWrite Off),以防止遮挡后方物体
// 透明 Pass 中的典型设置
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

关闭深度写入会带来新问题:同一模型多个面的渲染顺序无法保证,可能出现错误的自遮挡效果。

深度预写(Depth Prepass)#

一种解决透明渲染问题的技术:使用两个 Pass,第一个 Pass 只写入深度、不输出颜色;第二个 Pass 进行正常的透明混合,此时已有正确的深度信息可供测试。

在 URP 中,第一个 Pass 需要标记为 DepthOnly

Pass
{
Name "DepthOnly"
Tags { "LightMode" = "DepthOnly" }
ZWrite On
ColorMask 0 // 不写入任何颜色通道
}

摄像机深度图#

Unity 可以将深度缓冲的内容输出为一张可在 Shader 中采样的深度纹理(Camera Depth Texture)。这在后处理效果中广泛使用,例如:

  • 基于深度的运动模糊 — 利用当前帧和上一帧的深度信息计算每个像素的运动速度
  • 基于深度法线的描边 — 通过相邻像素深度差检测边缘
  • 软粒子 — 让粒子与场景几何体边缘平滑过渡

相关知识#

  • 渲染队列 — Unity 控制渲染顺序的机制,与深度缓冲密切相关
  • 法线贴图 — 另一种提升视觉质量而不增加几何复杂度的技术
深度缓冲
https://fuwari.vercel.app/wiki/depth-buffer/
Author
Qingswe
Published at
2024-07-06
License
CC BY-NC-SA 4.0