一步步学习计算机视觉in IOS(三)OpenGL渲染-3D遮盖问题处理

image.png

在绘制3D场景时,为了尽可能的逼真需要有近大远小的效果,而且可能会出现互相遮盖的情况。

image.png

对于OpenGL中渲染的多边形而言,遮盖的问题同样存在,一个物体在光照下是有两面的:阳面(光照覆盖的面)和阴面(背光的面),上图中黄色部分就是我们理解的阳面,黑色即为阴面,但是上图的甜甜圈
看起来特别奇怪,本该显示阳面的部分确显示了阴面。OpenGL需要判断当前需要展示的渲染数据。

如果我们不进行判断,那么OpenGL不知道该显示哪些界面,只根据绘制的先后顺序决定显示结果,就会导致本来是观察者不应该看到且该丢弃部分,不仅看到了,而且没有将隐藏部分丢弃。

不进行判断的后果

下面让我们使用lines图元来看下为何会黑化。


image.png
image.png

在渲染系统中,各种复杂的图像都是由普通的三角形组成的。因为我们没有处理覆盖问题,OpenGL不知道1和2两个图元的渲染顺序,导致图元2中的黑色元素替换了1中的元素,出现黑色。

正背面剔除

那么,如果OpenGL可以做到检查所有正面朝向观察者的面,可以轻松地获取渲染顺序。此外,背后朝向的面则不再渲染,也可以节约片元着色器的性能。

OpenGL是通过分析顶点顺序来区分正背面的,默认情况下是按照逆时针顶点连接顺序的三⻆形⾯为正面,按照顺时针顶点连接顺序的三角形⾯为背面。

image.png

那么,我们只要渲染正面图元1,不渲染反面图元2,就可以得到正确的渲染数据。

但是,有没有可能相互覆盖的图元都是正面的呢?这也是有可能的。

1
2

如上图所示,图1中的两块图元区域都是正面的,如果旋转到这两块区域重叠,那么正背面剔除法是无法解决的。

image.png

深度混合

就上图的情况,如何渲染是依赖于观察者的。对观察者而言,离观察者更近的区域应该渲染。那么如何定义渲染物体与观察者的距离呢?为了解决这个问题,就需要引入深度以及深度缓冲区的概念:

  • 深度是指OpenGL坐标系中,像素点的Z坐标距观察者的距离

深度与图形中像素点的Z坐标有如下关系:
如果观察者在Z轴的正方向,Z值越大则越靠近观察者
如果观察者在Z轴的负方向,Z值越小则越靠近观察者

  • 深度缓冲区是用来存储绘制到屏幕上每一个像素点的深度信息的—块内存缓冲区。它为每个像素存储一个深度值(z值),深度缓冲区的大小和颜色缓冲区(Frame Buffer)的大小一致。

在代码中,我们此次刷新时都要清空的数据中,就有深度缓冲区:

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

深度测试

一个物体在绘制时,像素点新的深度值需要与深度缓存中已经存在的深度值作比较,如果 新值 > 旧值,说明该像素点离观察者较远,丢弃新像素不绘制,反之,将新的深度值更新至深度缓存区,绘制新像素

Z-Fighting(Z冲突,闪烁)问题

深度测试中比对了像素的Z值,那么如果Z值相等,或者说差值极小呢?这就会带来Z-Fighting问题。

image.png

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

//开启Polygon Offset
glEnable(GL_POLYGON_OFFSET_FILL)
//指定偏移量
//参数一般填 -1 和 -1
glPolygonOffset (GLfloat factor, GLfloat units);
// 关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL);

混合

在深度测试中,我们直接用深度较浅的图元的渲染数据替换了之前的渲染数据,但是如果我们想让遮盖的新图元透明,那么就需要进行颜色混合了。

OpenGL渲染时会把颜色值存在颜⾊缓存区中,每个⽚段的深度值也是放在深度缓冲区。

  • 当深度缓冲区被关闭时,新的颜色将简单地覆盖原来颜色缓存区存在的颜色值。
  • 当深度缓冲区再次打开时,新的颜⾊片段只是当它们比原来的值更接近邻近的裁剪平⾯才会替换原来的颜⾊片段。
//开启混合
gl_Enable(GL_BIEND);
  • ⽬标颜色:已经存储在颜色缓存区的颜色值 (已经存在的颜色,旧颜色)
  • 源颜色:作为当前渲染命令结果进入颜色缓存区的颜⾊值 (新进来的颜色 ,新颜色)
    混合后的颜色有颜色方程式决定:
//Cf: 最终计算参数的颜⾊
//Cs: 源颜⾊
//Cd: 目标颜⾊
//S: 源混合因⼦,源Alpha混合因子
//D: ⽬标混合因⼦,⽬标Alpha混合因子
Cf = (Cs * S) + (Cd * D);

你可能感兴趣的:(一步步学习计算机视觉in IOS(三)OpenGL渲染-3D遮盖问题处理)