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

2020-07-13  本文已影响0人  milawoai
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

深度混合

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

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

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

 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);
上一篇 下一篇

猜你喜欢

热点阅读