四、OpenGl 表面剔除算法

439 阅读3分钟

一、绘制甜甜圈

核心代码

//void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
//参数1:GLTriangleBatch 容器帮助类
//参数2:外边缘半径
//参数3:内边缘半径
//参数4、5:主半径和从半径的细分单元数量
gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);

使用默认函数gltMakeTorus,初始化一个torusBatch批次类用来进行绘制。

绘制结果

绘制结果

但是进行旋转后,出现了渲染bug

绘制错误

二、油画算法

按照图层添加的顺序,依次进行绘制。重合的部分,会被后面绘制的片元信息覆盖。

缺点:

  1. 会对重叠的片元进行多次写操作,速度慢。
  2. 对于独立的三角形进行排序,开销过高。
  3. 如果三个三角形,两两叠加,就无法处理。如下图所示

甜甜圈出现的问题

三、油画算法解析甜甜圈

图片来源:康奈尔大学:计算机图形学入门

为了看清楚构造,为我们设置多边形填充模式为线填充。

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

初始化的甜甜圈

如上图所示,甜甜圈的顶点数据所指代的三角形,是从内环到外环排列一圈后,然后绘制下一圈,最后绘制的一圈和最开始绘制的接在一起。 且一圈中,排列起点是内环中间,经过外环,旋转布局一圈后,再次回到内环中间。

如上图所示,红色表示靠近观察者的一面,黑色是和红色三角形平行的,且远离观察者的一面。
由于同一个环中,远离观察者的一面先绘制,因此后绘制的内容会修改重叠部分片元信息,最终呈现的是靠近用户侧的颜色。
此时,如果使用默认光源,靠近用户侧的一侧,会渲染成红色,而远离用户侧的会渲染成黑色。
两个因素叠加,颜色正常显示。

旋转后的甜甜圈

甜甜圈绕 y 轴逆时针旋转,前后对应的三角形发生错位

上半部分

黑1渲染 -> 红1渲染 -> 黑2渲染 -> 红2渲染 -> 黑3渲染 -> 红3渲染

此时:
黑1 的右半部分,被后渲染的 红1 覆盖。
红1 的后半部分,被后渲染的 黑2 覆盖。
黑2 的后半部分,被后渲染的 红2 覆盖。 ...

下半部分

如上图所示,解释了为什么甜甜圈颜色开始错乱的时候,总是错一半。

由于甜甜圈是围成的一个环,所以上下两部分或者左右两部分,绘制的方向是相反的。

黑1渲染 -> 红1渲染 -> 黑2渲染 -> 红2渲染 -> 黑3渲染 -> 红3渲染

此时:
黑1 被后渲染的 红1 和 红2 覆盖。
黑2 被后渲染的 红2 和 红3 覆盖。 ...

四、OpenGL 表面剔除算法

OpenGL 对三角形的旋转方向进行定义。 面对观察者的方向为正面,把正面的三角形旋转方向定义为正,则与此旋转方向相反的三角形都是背面。
默认逆时针旋转三角形为正面。

图片来源: LearnOpenGL-CN

在甜甜圈案例中,虽然我们设置的三角形都是逆时针旋转的,但是由于表面发生了折叠,远离观察者的一面,开起来就是逆时针旋转了,就变成了背面。

如果我们开启了 背面剔除,此时黑色部分,即远离观察者的一面不会被渲染,也就不再出现错乱的现象。

五、表面面剔除参数解析

开启表面剔除(默认剔除背面)

glEnable(GL_CULL_FACE);

关闭表面剔除

glDisable(GL_CULL_FACE);

用户选择剔除哪个面,正面/背面/全部
GL_FRONT, GL_BACK, GL_FRONT_AND_BACK , 默认GL_BACK

glCullFace(GL_FRONT);

用户指定绕序哪个为正面。默认逆时针三角形为正面
GL_CW,GL_CCW 逆时针/顺时针

glFrontFace(GL_CW);