OpenGL入门第5课--正背面剔除

      在上一节说深度测试的时候,举了个例子:物体A被物体B遮档了一部分,在不开启深度测试的状况下若是咱们先绘制一个距离⽐较近的物体(B),再绘制距离较远的物体(A),则距离远的位图由于后绘制,会把距离近的物体覆盖掉。有人说那么能够先绘制较远的物体A,而后再绘制比较近的物体B,确实这样绘制是没有问题的,这也就是所谓的油画算法。可是,想象一下,若是采用油画算法被遮挡的那一部分像素是否是绘制了屡次,这是否是就多了不少开销,浪费了很多GPU性能。因此必要的时候开启深度测试是一个很不错的选择。不过呢今天我要说的是另一个提高性能的技巧——正背面剔除算法

为何要使用正背面剔除

        假设有个正方体,想一想从一个方向你最多能看到几个面。只要你不是透视眼无论你从哪一个方向最多都不会超过3个面。那么对于那些看不到的面咱们为何要去绘制呢?bash

      咱们能够假定把任何物体都只分为两个面,正面和背面。当前角度可以看到的叫作正面;看不到的叫作背面。而OpenGL正好能够作到检查全部正⾯朝向观察者的面,并渲染它们;丢弃背面朝向观察者的面. 这样能够节约片元着⾊器的性能.post

环绕顺序

        那么如何告诉OpenGL你绘制的图形哪一个是正面,哪一个是背面呢?OpenGL使用了一个很聪明的技巧,分析顶点数据的环绕顺序。性能

      在定义一组三角形顶点时,会以特定的环绕顺序来定义它们,多是顺时针(Clockwise)的,也多是逆时针(Counter-clockwise)的。每一个三角形由3个顶点所组成,咱们会从三角形中间来看,为这3个顶点设定一个环绕顺序.以下图:
测试

                             

       首先定义了顶点1,以后能够选择定义顶点2或者顶点3,这个选择将定义了这个三角形的环绕顺序。下面的代码展现了这点:
ui

float vertices[] = {
    // 顺时针
    vertices[0], // 顶点1
    vertices[1], // 顶点2
    vertices[2], // 顶点3
    // 逆时针
    vertices[0], // 顶点1
    vertices[2], // 顶点3
    vertices[1]  // 顶点2  
};复制代码

        每组组成三角形图元的三个顶点就包含了一个环绕顺序。OpenGL在渲染图元的时候将使用这个信息来决定一个三角形是一个正向三角形仍是背向三角形。默认状况下,逆时针顶点环绕所定义的三角形将会被处理为正向三角形。 spa

         在定义顶点顺序的时候,你应该想象对应的三角形是面向你的,因此你定义的三角形从正面看去应该是逆时针的。这样定义顶点很棒的一点是,实际的环绕顺序是在光栅化阶段进行的,也就是顶点着色器运行以后。这些顶点就是从观察者视角所见的了。code

         观察者所面向的全部三角形顶点就是咱们所指定的正确环绕顺序,而另外一面的三角形顶点则是以相反的环绕顺序所渲染的。这样的结果就是,咱们所面向的三角形将会是正向三角形,而背面的三角形则是背向三角形。下面这张图显示了这个效果:
cdn

                         

      上图中对于左右两个三角形,咱们在定义其顶点数据时,都应该以正向面对对应三角形的角度来定义,而且是逆时针定义。这样正面的三角形是一、二、3,背面的三角形也是一、二、3(若是咱们从其对应正面看这个三角形的话))。然而,若是从观察者当前视角使用一、二、3的顺序来绘制的话,从观察者的方向来看,背面的三角形将会是以顺时针顺序渲染的。虽然背面的三角形是以逆时针定义的,它如今是以顺时针顺序渲染的了。这正是咱们想要剔除(Cull,丢弃)的不可见面了!blog

相关API

     OpenGL为咱们提供了便捷的剔除背面的API,可是默认状况下是禁用的,因此若是想要利用OpenGL的正背面剔除功能就必须提早开启它。

glEnable(GL_CULL_FACE);复制代码

        这一句代码以后,全部背向面都将被丢弃再也不渲染。这样在渲染片断的时候可以节省50%以上的性能,但注意这只对像立方体这样的封闭形状有效。当在特定场景下须要某些2个面均可见的图形的时候,咱们必需要再次禁用它,由于它们的正向面和背向面都应该是可见的。

glDisable(GL_CULL_FACE); //禁用正背面剔除复制代码

         OpenGL还容许咱们改变须要剔除的面的类型。若是咱们只想剔除正向面而不是背向面会怎么样?咱们能够调用glCullFace来定义这一行为

glCullFace(GL_FRONT);//GL_FRONT 剔除正面   GL_BACK ,默认值,表示剔除背面  GL_FRONT_AND_BACK 2个面都剔除复制代码

       也能够经过调用glFrontFace,告诉OpenGL咱们但愿将顺时针的面(而不是逆时针的面)定义为正向面:

glFrontFace(GL_CCW);//默认值是GL_CCW,它表明的是逆时针的环绕顺序,另外一个选项是GL_CW,它(显然)表明的是顺时针顺序复制代码

        正背面剔除对于不透明的凸面体是完美的, 可是对于透明物体,或者是凹面体则不适用。


相关文章
相关标签/搜索