1)直观理解
深度其实就是该象素点在3d世界中距离摄象机的距离,深度缓存中存储着每个象素点(绘制在屏幕上的)的深度值!深度测试决定了是否绘制较远的象素点(或较近的象素点),通常选用较近的,而较远优先能实现透视的效果!!!
2)Z值(深度值)、Z buffer(深度缓存)
下面先讲讲Z坐标。Z坐标和X、Y坐标一样。在变换、裁减和透视除法后,Z的范围为-1.0~1.0。DepthRange映射指定Z坐标的变换,这与用于将X和Y映射到窗口坐标的视口变换类似,但DepthRange映射又与视口映射有所不同,因为深度缓存的硬件方案对应用程序来说是隐藏的。调用DepthRange的参数是[0.0,1.0],与一片断相联的Z值(深度值)表示到眼睛的距离。在默认情况下,最接近眼睛的片断(在近截面上)被映射到0.0,离眼睛最远的片断(在远截面上)映射到1.0。片断可以映射为深度缓存范围的子集(通过在DepthRange中指定更小的值)。映射也可以相反,这样的话离眼睛最远的片断在0.0,最近的片断在1.0(调用DepthRange(1.0,0.0)),虽然这样反向映射是可以的,但对实际应用作用不大。
要理解为什么渲染质量上会不一致,最重要的是要理解屏幕Z坐标的特性。Z值指定了从片断到眼睛的距离。在正交投影中距离和Z值的关系是线性的,但在透视投影中却不是的。在透视投影中这种关系是非线性的,而且非线性的程度与Frustum函数中的far/near(或gluPerspective函数中的zFar/zNear)成比例。这种非线性在靠近近截面时增加了Z值的精度,而且增加了深度缓存的效率;但是在视见体的其它部分则降低了精度,也就减少了深度缓存的精确性。根据经验,far/near比值大于1000会有这种不好的效果。所以一般far/near比值应小于1000。要想解决这个问题,最简单的方法是通过将近截面远离眼睛来降低far/near比值,其唯一的副作用是离眼睛很近的物体可能会被裁减掉,但在特定的应用程序中这很少是个问题,近截面的位置对X、Y坐标的投影没有影响,因此这对图像的影响很小。
还有OpenGL光栅化和深度缓存的一些其他方面值得一提。一个大问题是光栅化过程使用不精确的算法,所以很难处理共面的图元,除非它们共享相同的平面方程。这个问题在有限精度的深度缓存实现中更加严重。这些问题包括:贴花(decaling)、隐藏线消除、轮廓多边形和阴影等。不过现在已经提出许多方法来解决这些问题,如PolygonOffset技术等。
深度缓存的位数是衡量深度缓存精度的参数。深度缓存位数越高,则精确度越高,目前的显卡一般都可支持16位的Z Buffer,一些高级的显卡已经可以支持32位的Z Buffer,但一般用24位Z Buffer就已经足够了。
3)深度测试
OpenGL中的深度测试是采用深度缓存器算法,消除场景中的不可见面。在默认情况下,深度缓存中深度值的范围在0.0到1.0之间,这个范围值可以通过函数:
glDepthRange (nearNormDepth, farNormalDepth);
将深度值的范围变为nearNormDepth到farNormalDepth之间。这里nearNormDepth和farNormalDepth可以取0.0到1.0范围内的任意值,甚至可以让nearNormDepth > farNormalDepth。这样,通过glDepthRange函数可以在透视投影有限观察空间中的任意区域进行深度测试。
另一个非常有用的函数是:
glClearDepth (maxDepth);
参数maxDepth可以是0.0到1.0范围内的任意值。glClearDepth用maxDepth对深度缓存进行初始化,而默认情况下,深度缓存用1.0进行初始化。由于在进行深度测试中,大于深度缓存初始值的多边形都不会被绘制,因此glClearDepth函数可以用来加速深度测试处理。这里需要注意的是指定了深度缓存的初始化值之后,应调用:
glClear(GL_DEPTH_BUFFER_BIT);
完成深度缓存的初始化。
在深度测试中,默认情况是将需要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新帧缓存中对应像素的颜色值。这种比较测试的方式可以通过函数:
glDepthFunc(func);
进行修改。其中参数func的值可以为GL_NEVER(没有处理)、GL_ALWAYS(处理所有)、GL_LESS(小于)、GL_LEQUAL(小于等于)、GL_EQUAL(等于)、GL_GEQUAL(大于等于)、GL_GREATER(大于)或GL_NOTEQUAL(不等于),其中默认值是GL_LESS。这些测试可以在各种应用中减少深度缓存处理的的计算。