OpenGL隐藏面消除解决方案

3,448 阅读3分钟

渲染过程中可能产生的问题

在绘制3D场景的时候,我们需要决定哪些部分是对观察者可见的,或者哪些部分是对观察者不可⻅的。对于不可⻅的部分,应该及早丢弃。例如在⼀个不透明的墙壁后,就不应该渲染。这种情况叫做“隐藏面消除”(Hidden surface elimination).

image.png

解决方案一:油画算法

  • 先绘制场景中离观察者较远的物体,再绘制较近的物体。
  • 例如下面的图例,先绘制红色部分,再绘制黄色部分,最后再绘制灰色部分,即可解决隐藏面消除的问题。

image.png

弊端

  • 如果三个三角形是叠加的情况,油画算法将无法处理。

image.png

解决方案二:正背面剔除

背景

想象一个3D图形,从任何一个方向观察,总是会有看不到的面,那么我们为何要多此一举去绘制那些根本看不到的面呢,如果我们能以某种方式去丢弃这部分看不到的数据,OpenGL渲染性能即可提升超过50%。

如何知道某个面在观察者的视野中会不会出现?

  • 任何平面都有2个面,正面/背面。意味着你一个时刻只能看到一面。
  • OpenGL可以做到检查所有正面朝向观察者的面并渲染它们,从而丢弃背面,这样可以节约片元着色器性能。

如何告诉OpenGL我绘制的图形哪个面是正面?

  • 通过分析顶点数据的顺序

image.png

GLfloat vertices[] = { 
//顺时针
vertices[0], // vertex 1
vertices[1], // vertex 2 
vertices[2], // vertex 3 
// 逆时针
vertices[0], // vertex 1
vertices[2], // vertex 3
vertices[1]  // vertex 2
};
  • 正面:按照逆时针顶点连接顺序的三角形面
  • 背面:按照顺时针顶点连接顺序的三角形面

分析立方体中的正背面

image.png

  • 左侧三角形顶点顺序为:1 -> 2 -> 3;右侧三角形的顶点顺序为1 -> 2 -> 3
  • 当观察者在右侧时,则右边的三角形方向为逆时针方向则为正面,而左侧的三角形为顺时针则为背面。
  • 当观察者在左侧时,则左边的三角形为逆时针方向判定为正面,右侧的三角形为顺时针判定为背面。

总结

正面和背面是由三角形的顶点定义顺序和观察者方向共同决定的,随着观察者的角度方向的改变,正面背面也会跟着改变。

实际代码操作

  • 开启表面剔除(默认背面剔除)
void glEnable(GL_CULL_FACE);
  • 关闭表面剔除(默认背面剔除)
void glDisable(GL_CULL_FACE);
  • 用户选择剔除哪个面(正面/背面)
void glCullFace(GLenum mode);
mode参数为: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK, 默认GL_BACK
  • 用户指定OpenGL环境正面的三角形顶点环绕顺序
void glFrontFace(GLenum mode);
mode参数为:GL_CW(顺时针),GL_CCW(逆时针),默认值为GL_CCW
  • 例:剔除正面实现(1)
glCullFace(GL_BACK);
glFrontFace(GL_CW);
  • 例:剔除正面实现(2)
glCullFace(GL_FRONT);