OpenGL 渲染之深度测试
2020-07-12 本文已影响0人
徐徐图之哈哈
隐藏面消除成功解决了3D隐藏面直接丢弃,不绘制,只绘制可见部分。但是旋转3D会出现新的问题,如下图:
截屏2020-07-12 下午4.34.55.png接下来让我们来了解深度测试的神奇之处
深度测试 (DepthTest)
- 本身其实就是另外一种高效消除隐藏表面的技术
- 在绘制一个像素时,将一个值(Z值)分配给它,这个值表示它到观察者的距离
深度测试能干什么呢?
- 如上图甜甜圈旋转时,二个部分重叠时,此时的OpenGL不能清楚分辨哪个图层谁先谁后,结果就出现如图所示的好像被啃一口的现象
- 这个就可以用深度测试来解决且在绘制多个对象时能够进一步解决性能问题
注:为什么深度测试在绘制多个对象时能够进一步解决性能问题?
- 背面剔除能够消除位于对象背面的三角形,如果是重叠的独立对象呢?
- 其根本是依据油画算法:先简单地绘制背景,然后在上面绘制较近的对象。
- 这样做可能只要在画布上进行次数不多的绘制(对手工绘制时更加有用),但对于图形硬件来说,这样做会导致在同一个片段区域重复进行绘制,每一次绘制都会产生性能开销。
- 如果开销过大则导致光栅化过程变慢,将这种方式称为“填充受限”。
- 若将油画算法颠倒过来使用,实际上将会加速填充性能。
- 首先绘制离观察者较近的对象,然后再绘制较远的对象。
- 深度测试将消除那些应该被已存在像素覆盖的像素,这将节省可观的存储器带宽。
深度
- 在OpenGL坐标系中,像素点的Z坐标距离观察者的距离
注意:
- ==若观察者在Z轴的正方向,Z值越大则越靠近观察者==
- ==若观察者在Z轴的负方向,Z值越小则越靠近观察者==
深度缓冲区(DepthBuffer)
- 存储在显存中的特定内存区域,存储了屏幕上每个像素的深度值
注意:
- 深度值(Z值)越大,离观察者越远
- 深度值(Z值)越小,离观察者越近
使用深度测试
- 深度缓冲区,一般由窗口管理系统,GLEW创建,深度值一般由16位,24位,32位值表示,通常是24位,位数越高,深度精确度更好
- 开启深度测试
glEnable(GL_DEPTH_TEST);
- 在绘制场景前,清除颜色缓存区,深度缓冲
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- 清除深度缓存区默认值为1.0,表示最大的深度值,深度值的范围为(0,1)之间,值越小表示越靠近观察者,值越大表示越远离观察者
指定深度测试判断式
- 指定深度测试判断模式
void glDepthFunc(GLEnum mode);
截屏2020-07-12 下午9.53.05.png
打开/阻断 深度缓存区写入
void glDepthMask(GLBool value);
GL_TURE 开启深度缓冲区写入,GL_FALSE 关闭深度缓冲区写入
ZFighting闪烁问题
-
开启深度测试后,由于深度缓冲区精度的限制对于深度相差非常小的情况下,OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测,显示交错闪烁的现象
截屏2020-07-12 下午9.58.06.png 截屏2020-07-12 下午9.57.59.png
ZFighting闪烁问题解决方案
- 1.启用Polygon Offset 方式解决
glEnable(GL_POLYGON_OFFSET_FILL)
参数列表:
GL_POLYGON_OFFSET_POINT 对应光栅化模式:GL_POINT
GL_POLYGON_OFFSET_LINE 对应光栅化模式:GL_LINE
GL_POLYGON_OFFSET_FILL 对应光栅化模式:GL_FILL
- 2.指定偏移量
void glPolygonOffset(Glfloat factor,Glfloat units);
参数一般设置为-1.0和-1.0
截屏2020-07-12 下午10.18.54.png
- 3.关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)
预防ZFighting闪烁
- 不要将二个物体靠的太近,避免渲染时三角形叠在一起
- 尽可能将近裁剪面设置得离观察者远一些
- 使用更高位数的深度缓冲区