深度和深度缓冲区的由来
如果先绘制离观察者远的物体,再绘制近的物体,但观察者只看到近处的物体,远处的会被遮挡,不用呈现在屏幕上,这样做了不必要渲染和绘制, 如果先绘制离观察者近的物体,再绘制远的物体,因为远的物体后绘制,会把近的物体覆盖掉,因此OpenGL使用了个值来记录这个离观察者的距离,即深度,这样绘制的顺序就可以任意,只绘制近的物体,
深度与Z坐标的关系如下:
image图一观察者在Z轴的正方向,Z值越大则越靠近观察者,当物体的Z值大于观察者的Z值时,物体超出视野,不能显示
图二 观察者在Z轴的负方向,Z值越小则越靠近观察者,当物体的Z值小于观察者的Z值时,物体超出视野,不能显示
当观察者处于z=0的平面时,z值就是深度值。
深度值⼀般由16位,24位,32位值表示.通常是24位.位数越高,深度精确度越好。
图像的所有像素点,对应的深度值,显存开辟一块内存区域来保存,这个内存区域叫做深度缓冲区
在显存中,深度缓冲区(DepthBuffer)和颜色缓冲区(ColorBuffer)一一对应的,颜色缓冲区存储像素的颜色信息,而深度缓冲区存储像素的深度信息. 在开启深度测试后,默认深度比较规则的情况下,决定是否绘制一个物体表面和具体绘制什么颜色时,只显示距离观察者较近(深度值小)的像素点,
在渲染开始前,我们会将颜色缓冲区和深度缓冲区清空,深度缓冲区值全部清空为1.0,表示最大深度值(深度缓冲区值的取值范围是(0,1)),
渲染时首先将物体表面对应像素的深度值与当前深度缓冲区中的值进⾏比较. 如果⼤于深度缓冲区中的值,则表示距离观察者较远,这样的像素点不用显示在屏幕上,因此深度缓冲区和颜色缓冲区的数据保持不变,像素点被忽略;如果表面对应的像素值小于深度缓冲区中的值,表示表面距离观察者更近,用物体表面这个像素的深度值和颜色值更新深度缓冲区和颜色缓冲区中的值. 这个过程称为深度测试
image-
首先渲染前,如图1,颜色缓存去清空,深度缓冲区全部置为1,
-
当要渲染一个红色的矩形时,会将红色矩形的每个像素进行一次深度测试,由于此时深度缓冲区中的值全部为1,而红色矩形深度值会小于1,所以图2,会将红色矩形区域的颜色值和深度值更新到颜色缓冲区和深度缓冲区
-
图3,在图2的基础上叠一个蓝色的矩形,这所有的像素点又会再次进行深度测试,将距离观察者较近的(深度值较小的)像素点的深度值和颜色值存入深度缓冲区和颜色缓冲区,在叠加部分像素点,由于蓝色距离观察者更近,所以缓冲区更新了蓝色的颜色值和深度值
-
渲染完成后,将颜色缓冲区的数据提交,显示在屏幕
OpenGL允许修改深度测试中使用的比较运算符(一般开发者很少设置,直接使用默认模式)
//指定深度测试判断模式
void glDepthFunc(GLEnum mode);
mode可以选以下参数,默认GL_LESS,
imageOpenGL允许设置打开/阻断深度缓冲区的写入
void glDepthMask(GLBool value);
//value :
//GL_TURE 开启深度缓冲区写入;
//GL_FALSE 关闭深度缓冲区写⼊
程序使用深度测试流程
imageZFighting闪烁
由于深度缓冲区精度的限制,两个图形几乎在一个z平面时,深度缓冲没有足够的精度来决定两个形状距离较近(深度较小),导致这两个图形不断地在切换前后顺序,屏幕闪烁。这个现象叫做**深度冲突(Z-fighting) **,如下图所示
image
一个常用的解决方法就是让深度值之间产生间隔(Polygon Offset ,多边形偏移)-->解决ZFighting闪烁
glEnable(GL_POLYGON_OFFSET_FILL) //启用多边形偏移
//GL_POLYGON_OFFSET_POINT:对应光栅化模式: GL_POINT
//GL_POLYGON_OFFSET_LINE :对应光栅化模式: GL_LINE
//GL_POLYGON_OFFSET_FILL:对应光栅化模式: GL_FILL
glPolygonOffset(-1,-1);//指定偏移量
glPolygonOffset 需要2个参数: factor , units。每个Fragment的深度值都会增加如下所示的偏移量:
Offset = ( m * factor ) + ( r *units); m是指多边形的深度的斜率的最大值,一个多边形越是与近裁剪⾯平⾏,m就越接近于0. r是指能产⽣于窗⼝坐标系的深度值中可分辨的差异最⼩值,它是由具体OpenGL平台指定的一个常量.一个大于0的Offset 会把模型推到离你(摄像机)更远的位置,相应的一个小于0的Offset会把模型拉近。一般而言,只需要将-1.0 和 -1 这样简单赋值给glPolygonOffset 基本可以满足需求.
用完关闭多边形偏移
glDisable(GL_POLYGON_OFFSET_FILL)
预防ZFighting闪烁,但不能完全避免
- 不要把多个物体摆得太靠近,避免三角形重叠。通过在两个物体之间设置一个少量的到的偏移值,可以避免这两个物体之间的深度冲突。
- 尽可能将近平面设置远一些。深度的精度在靠近近裁剪时是非常高的,所以如果我们将近裁剪面远离观察者,我们将会对整个平截头体有着更大的精度。然而,将近平面设置太远将会导致近处的物体被裁剪掉,通常需要缇欧是来决定最适合场景的近裁剪面距离。
- 使用更高精度的深度缓冲。大部分深度缓冲的精度都是24位的,但现在大部分的显卡都支持32位的深度缓冲,这将会极大地提高精度。所以,牺牲掉一些性能,你就能获得更高精度的深度测试,减少深度冲突。
网友评论