標籤:

如何理解OpenGL中的backface culling以及圖形的正反面?

在學習OpenGL的過程中有一個問題一直困擾我很久,比如空間中存在一個三角形,如果我開啟backface clipping,那麼相機切換到反面我是看不到任何東西,這是不是意味著空間中是不是存在著兩個貼在一起的一正一反的三角形?開啟backface clipping後,OpenGL就不渲染背面的三角形?

還有一種情況,如果有一個全封閉的Cube,我正視某一個面,如果開啟backface clipping,此時對面那個面會渲染嗎?如果按照上面的理解,如果一個primitive有兩個面,此時在Cube裡面有一個面其實是朝向我的,這個面還算是backface嗎?


正反面是依靠圖元(primitive)頂點的纏繞順序(winding order)來定義的。

具體來說,OpenGL 是在光柵化階段,根據圖元頂點在屏幕空間按順時針方向(clockwise)或逆時針方向(counter-clockwise)來定義正面:

OpenGL 通過 glFrontFace(GL_CW 或 GL_CCW) 來設定正面的纏繞順序, 預設是 GL_CCW。

這個順序和頂點法線沒有直接關係(但通常預備的數據要一致)。

要注意不同圖元類型的定義,例如 GL_TRIANGLE_STRIP 的纏繞順序是會自動交錯來定義:


不是「一正一反的三角形」,也不是「一個primitive有兩個面」。根本沒有那個東西,除非你顯式地畫倆。而是:每個primitive是在用正臉對著你,還是在用屁股對著你。

primitive的右手頂點順序決定的那個法向量,如果在MVP變換之後向遠處指,那這個primitive就是屁股對著你的。反之就是正面對著你的。


題主可能混淆了Backface culling的作用。

Backface culling是加速渲染用的,而不是渲染本身。

你能看不看得見一個面跟有沒有backface culling沒有直接關係。

BFC的主旨是加速渲染,它先通過計算一個面的normal vector來定義什麼是「朝外的面,什麼是朝內的面」,因為不管怎樣,你都只能看到一個平面的一個面,此時的Normal Vector的朝向便是定義什麼是那個「你想要看到的面」。

然後remove掉那些朝外的,但是你看不到的面,計算出N和V之間的夾角,夾角大於180說明這個面是背向我的,說明不應該被渲染。

最後只留下NV夾角小於180度的面,如下圖

注意觀察茶壺嘴底部,BFC並沒有remove被壺身擋住的面,BFC只remove「沒有朝向camera的面」。被BFC後留下的這些面(如果沒有其他優化)不出意外都會被渲染。

至於題主所描述的「看不看得見」,那個不是BFC需要考慮的問題,那是Hidden surface removal的事。

Hidden surface removal的意思是「你不應該畫你看不到的面」。

這就涉及到了兩類渲染方式,一類是「Object Precision Algorithm」。

OPA下有「depth sort」和「Binary Space Partition」。這類渲染方式是先給Object排序,按照從遠到近的方式依次渲染。

另類是「Image Precision Algorithm」. 這類方法下有「Z-buffer」,「Warnock『s Algorithm」,「Ray Casting」,此類方法不會把一個object當作一個整體渲染,而是在每一個像素上判斷哪個object在此像素上的位置離Camera最近。然後挑最近的渲染。


如果是一個平面,backcull就沒多大必要了,因為你沒有機會同時看到正面和背面,記住無論正面背面,開啟cull也是有開銷的,這時候你可以選擇cull off。


推薦閱讀:

我的第一個 shadertoy 作品
openni,opencv,opengl這三個到底是什麼?有什麼關係?做什麼用?
Nehe OpenGL 教程是否過時?
為什麼ShaderToy選擇了GLSL?
在U3D等引擎當道的年代,我有沒有必要學opengl/dx或者osg???

TAG:OpenGL |