OpenGL学习笔记24-Face culling

Face culling 面选取

试着在心里想象一个3D立方体,数一数你能从任何方向看到的最大面数。如果你的想象力不太有创意,你可能会得到最多3个。你可以从任何位置和/或方向观看一个立方体,但你不能看到超过3个面。为什么我们要浪费时间去画另外3张我们看不见的面呢。如果我们可以以某种方式丢弃它们,我们将节省超过50%的立方体碎片着色器运行!

我们说超过50%而不是50%,是因为从某些角度看,只能看到两个甚至一个面。那样的话,我们可以节省50%以上。

这确实是一个很棒的想法,但我们需要解决一个问题:我们如何知道一个物体的面是否从观察者的角度看不见?如果我们想象一个闭合的形状,它的每个面都有两面。每一面要么面向用户,要么向用户显示背面。如果我们只能渲染面向观众的面呢?

这正是面部剔除所做的。OpenGL检查所有面向观众的面,并在丢弃所有面向观众的面时呈现这些面,节省了我们大量的片段着色器调用。我们需要告诉OpenGL我们使用的哪些面是正面哪些面是背面。通过分析顶点数据的缠绕顺序,OpenGL使用了一个聪明的技巧。

Winding order 缠绕顺序

当我们定义一组三角形顶点时我们用特定的绕圈顺序来定义它们要么顺时针,要么逆时针。每个三角形由3个顶点组成,我们按照从三角形中心看到的缠绕顺序指定这3个顶点。

 

正如你在图片中看到的,我们首先定义顶点1,然后从那里我们可以选择下一个顶点是2还是3。这个选项定义了这个三角形的缠绕顺序。下面的代码说明了这一点:


float vertices[] = {
    // clockwise
    vertices[0], // vertex 1
    vertices[1], // vertex 2
    vertices[2], // vertex 3
    // counter-clockwise
    vertices[0], // vertex 1
    vertices[2], // vertex 3
    vertices[1]  // vertex 2  
};

每个由3个顶点组成的三角形原语包含一个缠绕顺序。OpenGL在呈现原语时使用这些信息来确定三角形是面向前的还是面向后的。默认情况下,定义为逆时针顶点的三角形被处理为面向前方的三角形。

当定义顶点顺序时,将对应的三角形想象成它正对着你,所以指定的每个三角形都应该是逆时针的,就像你正对着那个三角形一样。像这样指定所有顶点很酷的一点是实际的缠绕顺序是在光栅化阶段计算的,所以当顶点着色器已经运行时。然后从观察者的角度来看这些顶点。

此时查看器所面对的所有三角形顶点确实按照我们指定的正确的绕圈顺序排列,但立方体另一侧三角形的顶点现在以一种将其绕圈顺序颠倒的方式呈现。结果是,我们面对的三角形被视为正面的三角形和背面的三角形被视为背面的三角形。下图显示了这种效果:

我们定义两个三角形的顶点数据按照逆时针的顺序(正面和背面三角形为1、2、3)。然而,从观众的方向顺时针呈现三角形如果我们画的顺序1、2和3的查看器的当前的观点。尽管我们以逆时针的顺序指定了后面的三角形,但它现在是以顺时针的顺序呈现的。这正是我们想要剔除(抛弃)不可见的面!

Face culling 面选取

在本章的开始我们说过,如果三角形原语被渲染为面向后的三角形,OpenGL可以丢弃它们。现在我们知道了如何设置顶点的缠绕顺序,我们可以开始使用OpenGL的face culling选项,这个选项在默认情况下是禁用的。

我们在前几章中使用的立方体顶点数据并没有按照逆时针的旋转顺序来定义,所以我更新了顶点数据以反映逆时针的旋转顺序,您可以从这里here.复制它。这是一个很好的实践,尝试并可视化这些顶点确实都是按逆时针顺序为每个三角形定义的。

要启用face culling,我们只需启用OpenGL的GL_CULL_FACE选项:


glEnable(GL_CULL_FACE);  

从这一点开始,所有不是正面的面都将被丢弃(试着在立方体内飞行,看看是否真的丢弃了所有的内面)。目前,如果OpenGL决定先渲染背面,我们可以在渲染片断上节省超过50%的性能(否则深度测试已经将它们丢弃了)。请注意,这只适用于像立方体这样的封闭形状。当我们从上一章中提取草叶时,我们必须再次禁用面部剔除,因为它们的正面和背面应该是可见的。

OpenGL也允许我们改变我们想要剔除的脸的类型。如果我们想要剔除正面而不是背面呢?我们可以用glCullFace定义这个行为:


glCullFace(GL_FRONT);  

glCullFace函数有三种可能的选项:

  • GL_BACK:只选择背面。
  • GL_FRONT:只选择正面。
  • GL_FRONT_AND_BACK:删除正面和背面。

glCullFace的初始值是GL_BACK。我们也可以通过glFrontFace告诉OpenGL我们更喜欢顺时针的脸而不是逆时针的脸:


glFrontFace(GL_CCW);  

默认值是GL_CCW,表示逆时针顺序,另一个选项是GL_CW,(显然)表示顺时针顺序。

作为一个简单的测试,我们可以通过告诉OpenGL,正面现在是由顺时针顺序而不是逆时针顺序来颠倒缠绕顺序:


glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);  

结果是只有背面被渲染:

 

注意,你可以创建相同的效果,通过剔除正面与默认的逆时针旋转顺序:


glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);  

正如你所看到的,面部剔除是提高OpenGL应用程序性能的一个很好的工具;特别是当所有的3D应用程序导出模型与一致的绕线订单(默认CCW)。你必须跟踪哪些对象会从面部剔除中受益,哪些对象根本不应该被剔除。

Exercises

  • Can you re-define the vertex data by specifying each triangle in clockwise order and then render the scene with clockwise triangles set as the front faces: solution
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值