OpenGL深度测试与深度缓冲以及Z-fighting的消除

1.深度:是指坐标系中像素点距离摄像机的距离,摄像机可能放在坐标系的任何位置,不能简单地说像素的z越大或越小就是越靠近摄像机。

2.深度缓冲区原理:就是把一个距离观察平面,也就是所谓的近裁剪面的深度值与窗口中每一个像素关联起来,这个深度值我么哦你吧它存储在一个统一的缓冲区中,那么这个缓冲区就被称为深度缓冲区。

3.深度值的产生过程:当GPU执行渲染时,首先要执行的是vertex shader,然后执行primitive Assembly(图元组装),个时候输出的z值是经过了MVP矩阵转换后的z值,那么还需要经过透视除法以及Depthrange之后生成的z值会对应每一个顶点都有一个z值,接下来这些顶点组成的图元,例如三角形,就回经过光栅化。在光栅化单元里会扫描整个三角形生成每一个片元,每一个片元对应屏幕上的一个像素,同时每一个片元都会有一个深度值,这个深度值则是用三角形的三个顶点的z值通过线性插值而得到的。

4.深度测试的过程:在opengl es2.0里面,深度测试被放在流水管线的Per-Fragment operation里面进行的,如果启用了深度缓冲区,那么在绘制每一个像素之前,会把它的深度值和已经存储在深度缓冲区的像素的深度值进行比较,因为深度值比较可以设置不同的比较函数,一般常用小于等于,因此如果新的像素深度值小于原来老的像素深度值,,新的像素值将取代原来老的像素值,则说明离摄像机更近,则会被保存下来,反之,新的像素值会被丢弃掉。

Fragment+Associated Data =>Pixel ownership test => Scissor Test => Multisample Fragment operations => stencil Test => Depth Buffer Test => Blending =>Dithering=>to Framebuffer

5. OpenGL es2.0的像素在执行完pixel shader以后,会输出一个fragment的片元,片元包含像素值以及深度值这种相关的数据,那么Fragment就会经过每个per-Fragment operation这个执行单元,最后才输出到FrameBuffer里面。

=》Per-Vertex Operation /Primitive Assembly => Rasterization => Per-Fragment Operation => FrameBuffer

6.开启深度测试方法:

在ES2.0里面,想要开启深度测试,需要先创建深度缓冲区,深度缓冲区一般有两种:(1)on-screen surface的深度缓冲(2)off-screen surface的深度缓冲区 FBO RBO

在深度缓冲区设置好以后,一般在每一帧的渲染之前,需要对深度缓冲进行清理操作,清理深度缓冲区的操作首先需要通过glcleardepthf()来设置清理时的深度值,一般在0.0~1.0之间,假如设为1.0,再调用glclear(GL_DEPTH_BUFFER_BIT),这就告诉GPU把深度缓冲所有的值设置成为1.0,最后开启深度测试,glEnable(GL_DEPTH-TEST),只有开启了深度测试,GPU在输出像素值的同时会去更新深度缓冲区的值,默认方式是less,可以通过glDepthFunc()设置比较函数。默认far和near的取值位1.0和0.0。

具体代码如下:

glClearDepth(1.0);

glclear(GL_Depth_Buffer_Bit);

glDepthFunc(GL_LESS);

7.Z-fighting与polygon offset

OpenGL es深度缓冲都会存在一个精度问题,这是因为深度缓冲的格式一般是16bit或者是24bit的精度,那么除非使用浮点数,否则都会有精度损失的问题。这种情况总是法正在两个几乎共面的surface上,它们在投影到近裁剪面的时候都会被赋予整型的深度值,当两个片元距离近裁剪面的深度值落在同一个区间的时候,它们的深度值是相等的。

Polygon offset的原理:

就是在Raster生产深度值以后,我们会再取稍微地改变这个深度值最后的值,改变公式为:

O=m*factor + r*units,其中r取决于GPU生产厂家,m=max{||}

Polygon offset就是位消除z-fighting而使用的,使用方法如下:

gl_Enable(GL_POLYGON_OFFSET_FILL);

glPolygonOffset(-1.0f,-1.0f);

注意Polygon offset的开启要放在两个可能发生z-fighting的面的绘制中间,用完之后在第二个面绘制完以后再关闭

glDisable(GL_POLYGON_OFFSET_FILL);

glPolygonOffset(-1.0,-1.0);

你可能感兴趣的:(OpenGL深度测试与深度缓冲以及Z-fighting的消除)