1. 程式人生 > >OpenGL學習腳印:背面剔除(Face Culling)

OpenGL學習腳印:背面剔除(Face Culling)

寫在前面
在繪製封閉型別的幾何物件時,開啟背面剔除功能能夠提高渲染效能。本節簡要介紹下背面剔除,示例程式可以在我的github下載

什麼是背面剔除

當我們觀察場景中物件時,一般只能以一定角度來觀察,那麼物件的某些面我們是看不到的,例如你觀察一個立方體,最多隻能同時看到3個面,有時只能看到1個面,而我們繪製時如果不採取剔除背面的措施,則要繪製6個面,其中包括一些,我們根本看不到的面。對於立方體這個面較少的幾何物件,效能開銷不明顯,但是對於複雜的模型,開啟背面剔除則能明顯改善渲染效能。 背面剔除,就是早點丟棄對觀察者來說是背面的片元的一種方法。

背面剔除的使用

上面提到,要早點丟棄對觀察者來說是背面的片元,那麼現在的問題是如何確定哪個面是背面的問題? OpenGL中使用頂點繞序(winding order)來確定。所謂繞序就是當幾何物件細分為三角形時,三角形頂點相對於中心的定義順序,具體如下圖所示(來自

opengl wiki):

頂點繞序

左邊的圖中指定頂點的順序是順時針的,右邊是逆時針的。

以三角面指向觀察者的方向為大拇指指向,其餘手指逆時針繞著大拇指,如果手指的繞向和三角面頂點繞向一致,則這個面為正面,否則為背面。

在OpenGL中,我們指定逆時針和順時針的三角形頂點如下:

   GLfloat 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 };

需要注意的是,三角形的正面還是背面這個是根據觀察者的觀察方向,而變動的。例如下面的圖中(來自www.learnopengl.com):

正方向問題

左側的三角形頂點順序為1->2->3,右側的三角形頂點順序為1->2->3。當觀察者在右側時,則右邊的三角形方向為逆時針方向為正面,而左側的三角形為順時針則為背面;當觀察者轉到左側時,左側的三角形為逆時針繞序判定為正面,而右側的三角形為順時針繞序判定為背面。可以看出正面和背面是由三角形的頂點定義順序和觀察者的觀察方向共同決定的,而且隨著觀察方向的改變,正面和背面將會跟著改變。

在OpenGL中開啟背面剔除需要使用:

   glEnable(GL_CULL_FACE);

同時OpenGL提供了函式glCullFace來供使用者選擇剔除哪個面:

API void glCullFace(GLenum mode);
mode引數為 GL_FRONT, GL_BACK, GL_FRONT_AND_BACK 3個列舉型別。預設為GL_BACK.

以及glFrontFace函式用來根據繞序指定哪個為正面:

API void glFrontFace(GLenum mode);
mode引數為GL_CW ,GL_CCW。預設值是GL_CCW。

如果要剔除正面,程式碼:

    glCullFace(GL_BACK);
    glFrontFace(GL_CW);

和下面的程式碼等價:

   glCullFace(GL_FRONT);

首先我們來對比下使用背面剔除和未使用背面剔除時,穿過立方體內部,我們看到的景象。下圖是沒有開啟背面剔除時:

未開啟背面剔除

可以看到,穿過內部時,看到了立方體後面的部分。當開啟了背面剔除時,穿過內部時,看不到立方體的背面:

開啟了背面剔除

當我們剔除正面時,觀察者的位置,決定了哪是正面,當觀察者處於立方體正面時,剔除正面看到效果:

剔除1個正面

當觀察者移動到可以看到立方體三個面時,判定正面,頂面和右側面為正面,則剔除正面後的效果為:

剔除三個正面

最後的說明

在使用背面剔除時需要注意,在指定物體表面的頂點時,頂點的順序需要定義為正向的逆時針順序。啟用背面剔除一般而言總能改善渲染效能,但是具體是否開啟背面剔除還是要根據應用場景而定。當渲染某些非封閉型別幾何物件,例如一顆草的模型時,則不需要開啟背面剔除。