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 OffBlend 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)。这在后处理效果中广泛使用,例如:
- 基于深度的运动模糊 — 利用当前帧和上一帧的深度信息计算每个像素的运动速度
- 基于深度法线的描边 — 通过相邻像素深度差检测边缘
- 软粒子 — 让粒子与场景几何体边缘平滑过渡