GLSL程式設計/GLUT/截面圖
本教程涵蓋了丟棄片段、確定渲染的是正面還是背面,以及正面剔除。本教程假設您熟悉在RGB立方體教程中討論的varying變數。
本教程的主要主題是剔除三角形或片段,即使它們是正在渲染的網格的一部分。主要有兩個原因:我們希望透過三角形或片段(就像左側圖中屋頂的情況,它只被部分切除)觀看,或者我們知道三角形無論如何都是不可見的;因此,我們可以透過不處理它來節省一些效能。OpenGL透過多種方式支援這些情況;我們將討論其中兩種。
以下著色器是一種非常簡單的剔除網格部分的方法:所有在物件座標系中具有正座標的片段都被剔除(即在其建模的座標系中;有關座標系的詳細資訊,請參見“頂點變換”)。以下是頂點著色器
attribute vec4 v_coord;
uniform mat4 m, v, p;
varying vec4 position_in_object_coordinates;
void main()
{
mat4 mvp = p*v*m;
position_in_object_coordinates = v_coord;
gl_Position = mvp * v_coord;
}
以下是片段著色器
varying vec4 position_in_object_coordinates;
void main()
{
if (position_in_object_coordinates.y > 0.0)
{
discard; // stop processing the fragment if y coordinate is positive
}
if (gl_FrontFacing) // are we looking at a front face?
{
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); // yes: green
}
else
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // no: red
}
}
當您將此著色器應用於任何預設物件時,它將剔除物件的一半。這是一種生成半球或開口圓柱體的非常簡單的方法。如果您啟用背面剔除
glEnable(GL_CULL_FACE);
您還會注意到物件的“內部”是不可見的。我們將在下面進一步討論背面剔除。
讓我們首先關注片段著色器中的discard指令。此指令基本上只是丟棄已處理的片段。(在早期的著色語言中,這被稱為片段“kill”;我可以理解片段更喜歡術語“discard”。)根據硬體的不同,這可能是一種相當昂貴的技術,因為一旦有一個著色器包含discard指令,渲染的效能可能會顯著下降(無論實際丟棄了多少片段,僅僅指令的存在就可能導致某些重要最佳化的停用)。因此,應儘可能避免使用此指令,尤其是在遇到效能問題時。
還有一點需要注意:片段discard的條件僅包含物件座標。結果是,您可以以任何方式旋轉和移動物件,並且被切除的部分將始終與物件一起旋轉和移動。您可能需要檢查在檢視或世界空間中切割的效果:更改頂點和片段著色器,以便在片段discard的條件中使用檢視座標或世界座標。提示:請參閱檢視空間著色教程,瞭解如何將頂點變換到世界空間。
您可以嘗試以下想法來改進著色器:將其更改為,如果座標大於某個閾值變數,則丟棄片段。然後引入一個uniform,允許使用者控制此閾值。提示:請參閱檢視空間著色教程,瞭解有關uniform的討論。
如著色器所示,片段著色器中提供了一個特殊的布林變數gl_FrontFacing,用於指定我們是否正在檢視三角形的正面。通常,正面面向網格的外部,背面面向內部。(就像表面法線向量通常指向外部一樣。)但是,區分正面和背面的實際方法是三角形中頂點的順序:如果攝像機以逆時針順序看到三角形的頂點,則它會看到正面。如果它以順時針順序看到頂點,則它會看到背面。
我們的片段著色器檢查變數gl_FrontFacing,如果gl_FrontFacing為true(即片段是正面三角形的一部分;即它面向外部),則將綠色分配給輸出片段顏色;如果gl_FrontFacing為false(即片段是背面三角形的一部分;即它面向內部),則分配紅色。事實上,gl_FrontFacing不僅允許您使用不同的顏色渲染表面的兩個面,還可以使用完全不同的樣式渲染。
請注意,基於三角形中頂點的順序來定義正面和背面可能會導致問題,當頂點被映象時,即使用負因子進行縮放。我們可以嘗試將內部翻轉到外部,方法是將一個(或三個)座標乘以-1,例如,在頂點著色器中以這種方式分配gl_Position
gl_Position = mvp * vec4(-v_coord.x, v_coord.y, v_coord.z, 1.0);
這只是將座標乘以-1。對於球體,您可能會認為什麼也不會發生,但它實際上會將正面變成背面,反之亦然;因此,現在內部是綠色的,外部是紅色的。(順便說一句,此問題也會影響表面法線向量。)因此,在使用映象時要小心!
我們看到可以使用glEnable(GL_CULL_FACE)來開啟三角形剔除。預設情況下,背面會被剔除,就像指定了glFrontFace(GL_CCW)一樣。您也可以使用glFrontFace(GL_CW)指定正面剔除。可以啟用背面剔除,因為物體的內部通常是不可見的;因此,背面剔除可以透過避免光柵化這些三角形來節省相當多的效能,如下所述。當然,我們能夠使用著色器看到內部,因為我們丟棄了一些片段;因此,在這種情況下,我們必須停用背面剔除。
剔除是如何工作的?三角形和頂點像往常一樣被處理。但是,在將頂點透過視口變換轉換到螢幕座標後(參見“頂點變換”),圖形處理器會確定三角形的頂點在螢幕上是按逆時針順序還是按順時針順序出現。根據此測試,每個三角形都被視為正面三角形或背面三角形。如果它是正面三角形並且啟用了正面三角形的剔除,則它將被丟棄,即停止處理它並且不進行光柵化。類似地,如果它是背面三角形並且啟用了背面三角形的剔除。否則,三角形將像往常一樣被處理。
恭喜你完成了另一個教程。(如果你嘗試過其中一項作業:幹得好!我還沒有。)我們已經瞭解了
- 如何丟棄片段。
- 如何啟用背面剔除。
- 如何以不同的顏色渲染正面和背面三角形。
如果你還想了解更多
- 關於頂點變換,例如從物件到世界座標的模型變換或到螢幕座標的視口變換,您應該閱讀“頂點變換”。
- 關於如何定義uniform,您應該閱讀關於視空間著色的教程。
| 返回OpenGL 程式設計 - 照明部分 | 返回GLSL 程式設計 - GLUT 部分 |