筆者介紹:姜雪偉,IT公司技術合伙人,IT高級講師,CSDN社區專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D游戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。
CSDN視頻網址:http://edu.csdn.net/lecturer/144
面剔除技術在游戲開發中主要目的是提高效率,在現實生活中也會經常遇到這種情況,比如我們觀看一幢大廈,我們在大廈的某個位置看,只能看到大廈的一到兩個面,其他的面我們是看不到的,因為被擋住了,但是這不妨礙我們看這幢大廈,在虛擬城市建模時,也會使用面剔除,城市漫游如果只是沿著道路行走,背對道路那一側的建筑面是永遠看不到的,美術可以使用一張面片代替,不需要再建復雜的面片,但是在游戲中模型的面我們不知道那個面是背對玩家的,因為在場景中模型是可以隨意移動和旋轉的。這就要用到游戲中的面剔除技術。
下面開始講游戲中的面剔除技術處理,游戲一般會采用DX或者OpenGL去做渲染,以OpenGL為例,它會檢查所有正面朝向(Front facing)觀察者的面,并渲染它們,而丟棄所有背面朝向(Back facing)的面,這樣就節約了我們很多片段著色器的命令(它們很昂貴?。?。我們必須告訴OpenGL我們使用的哪個面是正面,哪個面是反面。OpenGL使用一種聰明的手段解決這個問題——分析頂點數據的連接順序(Winding order)。
當我們定義一系列的三角頂點時,我們會把它們定義為一個特定的連接順序(Winding Order),它們可能是順時針的或逆時針的。每個三角形由3個頂點組成,我們從三角形的中間去看,從而把這三個頂點指定一個連接順序。

正如你所看到的那樣,我們先定義了頂點1,接著我們定義頂點2或3,這個不同的選擇決定了這個三角形的連接順序。下面的代碼展示出這點:
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};每三個頂點都形成了一個包含著連接順序的基本三角形。OpenGL使用這個信息在渲染你的基本圖形的時候決定這個三角形是三角形的正面還是三角形的背面。默認情況下,逆時針的頂點連接順序被定義為三角形的正面。
當定義你的頂點順序時,你如果定義能夠看到的一個三角形,那它一定是正面朝向的,所以你定義的三角形應該是逆時針的,就像你直接面向這個三角形。把所有的頂點指定成這樣是件炫酷的事,實際的頂點連接順序是在光柵化階段(Rasterization stage)計算的,所以當頂點著色器已經運行后。頂點就能夠在觀察者的觀察點被看到。
我們指定了它們以后,觀察者面對的所有的三角形的頂點的連接順序都是正確的,但是現在渲染的立方體另一面的三角形的頂點的連接順序被反轉。最終,我們所面對的三角形被視為正面朝向的三角形,后部的三角形被視為背面朝向的三角形。下圖展示了這個效果:

在頂點數據中,我們定義的是兩個逆時針順序的三角形。然而,從觀察者的方面看,后面的三角形是順時針的,如果我們仍以1、2、3的順序以觀察者當面的視野看的話。即使我們以逆時針順序定義后面的三角形,它現在還是變為順時針。它正是我們打算剔除(丟棄)的不可見的面!
下面進入OpenGL實際代碼操作,開啟OpenGL的GL_CULL_FACE選項就能開啟面剔除功能函數:
glEnable(GL_CULL_FACE);從這兒以后,所有的不是正面朝向的面都會被丟棄。目前,在渲染片段上我們節約了超過50%的性能,但記住這只對像立方體或者是模型這樣的封閉形狀有效。當我們繪制上個教程中那個草的時候,我們必須關閉面剔除,這是因為它的前、后面都必須是可見的。
OpenGL允許我們改變剔除面的類型,要是我們剔除正面而不是背面會怎樣?我們可以調用glCullFace來做這件事:
glCullFace(GL_BACK);glCullFace函數有三個可用的選項:
GL_BACK:只剔除背面。GL_FRONT:只剔除正面。GL_FRONT_AND_BACK:剔除背面和正面。glCullFace的初始值是GL_BACK。另外,我們還可以告訴OpenGL使用順時針而不是逆時針來表示正面,這通過glFrontFace來設置:
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);總結:關于面剔除操作,現在都是在Shader中加入一行命令行即可,面剔除操作是OpenGL優化的一個方面,其實現在市面上各種引擎功能都很成熟了,引擎已經為我們做了面剔除操作的事情,但是作為開發者,自己本身還是要明白其原理,這樣更有助于提升自己的技能。
新聞熱點
疑難解答