OpenGL之深度测试
问题出现
从上一篇正背面剔除我们看到了正背面剔除方法解决了隐藏面消除的问题了,但是引来了新的问题,就是当我们翻转物体到正背面重合时,会看到物体部位缺失。为什么会引起这个问题呢?
是因为在甜甜圈翻转过程中,当正背面重合时,OpenGL中并不能分清楚哪个是正面哪个是背面,谁显示在前,谁显示在后,所以导致了缺失。
所以下面我们来解决这个问题。
引入深度的概念
首先我们引入一个新概念,什么是深度?
深度:就是在OpenGL坐标系中,像素点的z坐标距离观察者的距离,由于观察者可以放在坐标系的任意位置,所以有正负的区分。所以不能简单的说z数值越大或越小,观察者就越靠近物体。
- 如果观察者在Z轴的正方向,Z值越大就越靠近观察者。
- 如果观察者在Z轴的负方向,Z值越小则越靠近观察者。
深度缓冲区(DepthBuffer):就是一块内存区域,存储在显存,专门存储着每个像素点(绘制在屏幕上的)深度值,深度值(z值)越大,则离观察者(摄像机)越远。
- 深度缓冲区的原理是把距离观察者平面(近裁减面)的深度值与窗口每个像素点1对1进行关联以及存储。比如200 * 200分辨率的屏幕,一共就有40000个存储深度值。
为什么需要深度缓存区呢?
因为在不使用深度测试时,如果我们要绘制两个距离屏幕远近不同的物体,那么我们得先绘制了距离远的物体,再绘制近的物体,才不会导致把近的物体遮盖住,绘制的顺序决定了显示的画面。而如果有了深度缓冲区,那么绘制两个距离远近不同的物体时,则不需要按照先远再近的顺序了。
深度测试:
开启后,在绘制每个像素之前,OpenGL按照默认的测试规则,会比较当前深度缓存区里的值,如果新的深度值离观察者更近,就替换原来的值写入缓存区,如果更远则丢弃这个值。同时也会把物体的这个像素点的颜色信息存入颜色缓存区,这样这个像素点的颜色和深度就更新了。除非调用glDepthMask(GL_FALSE)
来禁止写入。(开启深度缓存区写入就用glDepthMask(GL_TRUE)
)
我们可以通过glDepthFunc(GLenum func)
来修改深度测试的测试规则。
这是一个枚举函数:
深度值的计算:
深度值一般由16位、24位或者32位值表示,通常24位。现在也有些设备是64位的。位数越高,那么存储的深度值的精确度越高。深度值的范围在【0,1】之间,值越小就越靠近观察者,值越大就表示越远离观察者。
解决缺失的问题
这时候我们再回到开始的问题上。我们一样通过监听右键菜单栏的点击,来开启和关闭深度测试。触发在RenderScene的重新绘制。
RenderScene执行流程
开启和关闭函数
if(iDepth)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
我们再来看下执行的效果图。
可以发现深度测试的优势:
- 可用于处理当甜甜圈旋转中,2个部分重叠时, 此时OpenGL不能清楚分辨哪个图层在前 哪个图层在后出现的甜甜圈缺失的现象;
- 隐藏⾯消除,可以发现除了使用正背面剔除,还可以使⽤深度测试来解决。
总结
正背面剔除:需要根据顶点数据顺序来确定正背面,也就是可见面与隐藏面,隐藏面直接丢弃,不绘制,只绘制可见的面。
深度测试:可以一次性解决隐藏面消除问题,因为不需要知道正背面,只需要显示深度值离观察者近的面,剩余不可见的都丢弃。