在上一節說深度測試的時候,舉了個例子:物體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
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,它(顯然)表明的是順時針順序複製代碼
正背面剔除對於不透明的凸面體是完美的, 可是對於透明物體,或者是凹面體則不適用。