OpenGL基础之Depth Testing

就像color-buffer存储了所有片元的颜色一样,depth-buffer存储了每一个片元的深度信息。它是由窗口系统自动创建并存储深度值的,深度值的精度一般有16位、24位和32位float,比较常用的深度精度为24位。

当深度测试打开后,OpenGL会测试每个片元的深度值与depth-buffer中数值,如果测试通过,则会更新depth-buffer中的值,如果测试通不过,则会舍弃这个片元。

深度测试发生在片元着色器执行之后的屏幕空间,屏幕空间坐标与glViewport函数定义的视口大小直接相关,并且可以通过GLSL的内建变量gl_FragCoord来访问。gl_FragCoord代表了屏幕空间的坐标值(左下角为(0,0)),gl_FragCoord的z值就是片元的深度值,最后的深度测试就是对比这个值跟depth-buffer中的值。

现在大部分的GPU都支持一项称为early depth testing的特性,early depth testing允许在片元着色器执行之前进行深度测试,这样就可以避免那些根本看不到的片元进行片元着色,这样可以提高程序性能。但是,一旦使用了early depth testing,就不能再在片元着色器中写深度值。

OpenGL使用glEnable(GL_DEPTH_TEST)开启深度测试,一旦开启深度测试,必须每一帧都清理depth-buffer:

glclear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

也可以通过glDepthMask(GL_FALSE)来禁止对depth-buffer的写操作。

 

Depth test function

OpenGL允许修改深度测试的比较操作,通过制定一个比较函数,就可以指定深度测试的比较方式。这些可以通过函数glDepthFunc来制定:

glDepthFunc(GL_LESS);

具体的比较函数

Function

Description

GL_ALWAYS

测试永远通过

GL_NEVER

测试永远不通过

GL_LESS

当片元深度值小于depth-buffer中的深度值时通过

GL_EQUAL

当片元深度值等于depth-buffer中的深度值时通过

GL_LEQUAL

当片元深度值小于等于depth-buffer中的深度值时通过

GL_GREATER

当片元深度值大于depth-buffer中的深度值时通过

GL_NOTEQUAL

当片元深度值不等于depth-buffer中的深度值时通过

GL_GEQUAL

当片元深度值大于等于depth-buffer中的深度值时通过

 

Depth value precision

由于深度值的范围在0-1之间,它代表了所有在视锥体中间的物体离视点的远近。所以在near和far之间的距离最后都要映射到0-1之间。常用的透视投影下,推导出的深度公式如下:

 

 

从公式可以看出,深度值的分布是非线性的。它的值跟1/z成正比。也就是说越靠近近平面的地方,深度值的精度越高,越远则精度越差。比如z值在1.0-2.0之间,对应的深度值则分布在1.0-0.5之间,而z值在50.0-100.0之间,深度值则分布在0.02-0.001之间。如下图:

 

 这也是游戏当中出现z-fighting的主要原因,具体的解决方法有很多,比如使用reverse-z,或者使用logdepth的算法都可以避免远处深度值精度不够的问题,这里就不展开讲了,后面有时间会专门写一篇文章来讲。

posted @ 2017-12-12 10:33  DeepDream  阅读(2066)  评论(0编辑  收藏  举报