OpenGL深度测试

2020-07-11  本文已影响0人  奉灬孝

在上一篇OpenGL正背面剔除中提到了正背面剔除的弊端:如果前后两个点都是正面或是背面,这时OpenGL无法区分哪个面在前,哪个面在后,就可能出现下图所示的问题。

正背面区分问题.png

为了解决这个问题,就引出了深度测试

一、什么是深度?

1. 定义

深度其实就是该像素点在3D世界中距离观察者的距离—Z值

2.深度值计算

深度值⼀般由16位,24位或者32位值表示,通常是24位。位数越⾼高的话,深度的精确度越好。

深度缓冲主要是通过计算深度值来比较⼤小,在深度缓冲区中包含深度值介于 0.0 和 1.0 之间, 从观察者看到其内容与场景中的所有对象的 z 值进⾏了⽐较。这些视图空间中的 z 值可以在投影平头截体的近平面和远平面之间的任何值。我们因此需要一些方法来转换这些视图空间 z 值到 [0,1] 的范围内,下面的 (线性) 方程把 z 值转换为 0.0 和 1.0 之间的值 :


far和near是提供到投影矩阵设置可见视图截锥的远近值.png
3. Z值与观察者的关系

观察者可以放在坐标系的任意位置。所以,不能简单的说Z值越大或越小,观察者就越靠近物体。

二、什么是深度缓冲区?

1. 定义

深度缓存区,就是⼀块内存区域,专⻔门存储着每个像素点(绘制在屏幕上的)深度值。

2. 深度缓冲区在哪里?

深度缓冲区存储在显存中。

3. 深度缓冲区原理

深度缓冲区就是把距离观察者平面(近裁剪面)的深度值与窗口中的每个像素点1对1进行关联和存储。分辨率为 120 * 120 图片则存储 120 * 120 个深度值。

三、深度测试

深度缓冲区(DepthBuffer)颜⾊色缓存区(ColorBuffer)是对应的。颜⾊缓存区存储像素的颜⾊信息,⽽深度缓冲区存储像素的深度信息.。在决定是否绘制一个物体表面时,首先要将要绘制像素的深度值(新值)与当前深度缓冲区的深度值(旧值)进行比较。如果 新值 > 旧值,则丢弃这部分不进行绘制。否则,将这个像素对应的深度值和颜⾊色值—新值,更新到深度缓冲区和颜色缓存区。这个过程称为深度测试

深度测试主要函数
glEnable(GL_DEPTH_TEST);

在绘制场景前,清除颜⾊缓存区,深度缓冲。清除深度缓冲区默认值为1.0。

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
void glDepthFunc(GLEnum mode);
函数 说明
GL_ALWAYS 总是通过测试
GL_NEVER 总是不通过测试
GL_LESS 在当前深度值 < 存储的深度值时通过
GL_GREATER 在当前深度值 > 存储的深度值时通过
GL_EQUAL 在当前深度值 == 存储的深度值时通过
GL_LEQUAL 在当前深度值 <= 存储的深度值时通过
GL_GEQUAL 在当前深度值 >= 存储的深度值时通过
GL_NOTEQUAL 在当前深度值 != 存储的深度值时通过
//value: GL_TURE,开启深度缓冲区写入; GL_FALSE,关闭深度缓冲区写⼊
void glDepthMask(GLBool value);

四、正背面剔除问题解决

到这里上图中正背面剔除弊端的问题就迎刃而解了,开启深度测试将新旧深度值的对比,决定像素点是绘制还是丢弃,就不会出现分不清正背面的问题了。

设置深度测试开关

开启和关闭的逻辑,主要取决于右键菜单的点击次数,第一次打开,第二次关闭,以此类推

//根据设置iDepth标记来判断是否开启深度测试
    if(iDepth)
        glEnable(GL_DEPTH_TEST);
    else
        glDisable(GL_DEPTH_TEST);

五、深度测试ZFighting闪烁问题

开启深度缓冲区后,由于深度值精度的限制,对于相差非常小的深度值(比如在同一个深度进行2次渲染),就可能出现不能正确区分两个深度值的问题,导致测试的结果随机出现。所以,显示时2个画⾯交错出现,就会出现闪烁问题。如下图所示:


ZFighting闪烁问题.png
1. 解决方案 — 多边形偏移(Polygon Offset)

其问题产生的主要原因是由于图形靠的太近,导致无法区分出图层先后次序,针对该问题,OpenGL提供了一种多边形偏移(Polygon Offset)方案

glEnable(GL_POLYGON_OFFSET_FILL)
多边形偏移枚举值 对应的光栅化模式
GL_POLYGON_OFFSET_FILL GL_FILL
GL_POLYGON_OFFSET_LINE GL_LINE
GL_POLYGON_OFFSET_POINT GL_POINT
void glPolygonOffset(Glfloat factor, Glfloat units);
// 参数和开启的参数相同
glDisable(GL_POLYGON_OFFSET_FILL);
2. 问题预防
上一篇 下一篇

猜你喜欢

热点阅读