深度缓冲
维基百科,自由的百科全书
在计算机图形学中,深度缓冲是在三维图形中处理图像深度坐标的过程,这个过程通常在硬件中完成,它也可以在软件中完成,它是可见性问题的一个解决方法。可见性问题是确定渲染场景中哪部分可见、哪部分不可见的问题。画家算法是另外一种常用的方法,尽管效率较低,但是也可以处理透明场景元素。深度缓冲也称为 Z 缓冲。
当三维图形卡渲染物体的时候,每一个所生成的像素的深度(即 z 坐标)就保存在一个缓冲区中。这个缓冲区叫作 z 缓冲区或者深度缓冲区,这个缓冲区通常组织成一个保存每个屏幕像素深度的 x-y 二维数组。如果场景中的另外一个物体也在同一个像素生成渲染结果,那么图形处理卡就会比较二者的深度,并且保留距离观察者较近的物体。然后这个所保留的物体点深度保存到深度缓冲区中。最后,图形卡就可以根据深度缓冲区正确地生成通常的深度感知效果:较近的物体遮挡较远的物体。这个过程叫作 z 消隐。
深度缓冲的分辨率对于场景质量有很大的影响:当两个物体非常接近的时候,16 位的深度缓冲区可能会导致“z 缓冲区 fighting”的人为噪声;使用 24 位或者 32 位的深度缓冲区就会表现得较好;由于精度太低,所以很少使用 8 位的深度缓冲区。
目录 |
[编辑] 发展
即使深度缓冲区有足够大的分辨率,但是如果 z 缓冲区中距离精度不随距离均匀分布的话图像质量也可能会出现问题。距离较近的部分通常精度较高,这样近距离的物体显示质量也较高。通常这是所期望得到的结果,但是当物体距离变得较远时可能会出现人为误差。一种能够得到更加均匀分布精度的深度缓冲变体是 w缓冲。
在场景开始的时候,必须将深度缓冲区初始化为一个特定的值,通常初始化为 1.0,这是因为 1.0 是深度范围 0 到 1 的上限,它意味着在整个视体(viewing frustum)之内没有任何物体。
通常认为深度缓冲概念的发明主要归功于 Edwin Catmull,虽然 Wolfgang Straßer 也在 1974年 所写的博士论文 1 中提到了同样的思想。
在最近几年的 PC 图形卡上,深度缓冲管理需要使用大量的内存带宽。人们采用了各种各样的方法减少深度缓冲的影响,其中的方法有无损数据压缩(因为压缩/解压所消耗的计算机资源要比带宽的占用更加合算)。另外还使用了极快的硬件工具清除深度信息,这种方法完全取代了“一帧正、一帧负”这种利用有符号数巧妙地绕过帧间深度信息清除的技巧。
[编辑] z 消隐
在渲染过程中,z 消隐是根据深度信息对像素的早期剔除。当渲染隐藏表面所需要的计算量很大的时候,这种方法可以提升处理性能。z 消隐是深度缓冲的一个直接结果,在这种方法中每个待定像素的深度都要与相同位置的现存像素的深度进行比较。
使用深度缓冲区,一旦像素的深度已经确定,那么就可以对这个像素进行裁剪,这样如果该像素不可见的话就可以完全跳过照明与纹理处理的过程,并且需要消耗许多时间的像素浓淡工具通常也会跳过对于裁剪掉的像素的处理。这样 z 消隐就成为了在填充速度、光照、纹理或者像素浓淡处理是主要瓶颈的场合的一种很好的优化工具。
尽管深度缓冲可以处理未经排序的几何体,但是按照深度不断增加的方式(与画家算法排序方式相反)对多边形进行排序,每个像素就可以只渲染一次。对于填充速度有限但是有大量重复绘制场合,这种方法就可以提高处理性能。
[编辑] 数学基础
待渲染的照相机空间中的深度经常定义为近距 near 到远距 far 之间的 z 值,在透视变换之后,得到新的 z' 值:
其中 z 是照相机空间的值,它有时候也表示为 w 或者 w'。
结果 z' 是在 -1 到 1 之间归一化之后的值,其中近距 near 平面位于 -1 处,远距 far 平面位于 1 处。在这个范围之外的相应点在视图体之外,不需要进行渲染。
为了实现深度缓冲,在整个屏幕空间上的对当前多边形顶点之间进行插值来计算 z' 的值,通常这些中间数值在深度缓冲区中用定点数格式保存。距离近距 near 平面越近,z' 值越密;距离越远,z' 值越稀。这样距离照相机越近精度越高。near 平面距离照相机越近,则远距离位置的精度越低。near 平面距离照相机太近是在远距离物体产生人为误差的一个常见因素。
[编辑] w 缓冲
为了实现 w 缓冲,通常照相机空间中的 z 值或者 w 值都保存成浮点数格式,但是这些数值无法根据顶点在整个屏幕上进行线性插值——通常对它的倒数进行插值,然后再取倒数。这样得到的结果 w 值与 z' 不同,它们在 near 平面与 far 平面之间均匀分布。
根据应用的不同 z 缓冲与 w 缓冲生成的图像质量也有所不同。
[编辑] Javascript
当在 JavaScript 中使用 <canvas>
标签的时候,可以将下面的程序作为深度缓冲的公式。
//F=far, N=near, Z=final return f=0; n=0; z=0; z=((f+n)/(f-n))+((1/z)*((-2*f*n)/(f-n))); // Optimized: z=(f+n-2*f*n/z)/(f-n)
[编辑] 参见
- Edwin Catmull -- 深度缓冲概念的发明人
- 三维计算机图形
- 不规则深度缓冲
- Z-order
[编辑] 外部链接
[编辑] Notes
Note 1: see W.K. Giloi, J.L. Encarnação, W. Straßer. "The Giloi’s School of Computer Graphics". Computer Graphics 35 4:12–16.