在3D空間中繪製三角形
在OpenGL中,要繪製一個實心的表面,僅僅靠點和線是不夠的,還需要使用多邊形。多邊形是一種閉合的形狀,可以用當前選擇的顏色進行填充(也可以選擇不填充),它是OpenGL中所有實心物體的組成基礎。
最簡單的多邊形是三角形,它只有三條邊。圖元GL_TRIANGLES通過連接三個頂點,繪製三角形。
三角形 GL_TRIANGLES
環繞問題(winding)
頂點的指定次序以及方向的組合稱爲環繞。
在默認情況下,OpenGL認爲逆時針方向環繞的一面是多邊形的正面。這個問題十分重要,那是因爲我們常常希望爲一個多邊形的正面和背面分別設置不同的物理特性,如設置不同的顏色和反射屬性等。在同一個場景中,使所有的多邊形保持環繞方向的一致並使用正面多邊形來繪製所有實心物體的外表面是非常重要的。
如果想改變OpenGL的這個默認行爲,可以調用下面這個函數:
glFrontFace(GL_CW);
參數GL_CW告訴OpenGL順時針環繞的多邊形將被認爲是正面的;
參數GL_CCW告訴OpenGL逆時針環繞的多邊形將被認爲是正面的。
三角形帶 GL_TRIANGLE_STRIP
使用該圖元,可以繪製一串相連的三角形,從而節省大量時間。使用三角形帶而不是分別指定每個三角形有兩個優點:
1、 在用前三個頂點指定了第一個三角形之後,對於接下來的每個三角形,只需要再指定一個頂點。當需要繪製大量的三角形時,採用這種方法可以節省大量的程序代碼和數據存儲空間。
2、 提高了運算性能並節省了帶寬。更少的頂點意味着數據從內存傳輸到圖形卡的速度更快,並且頂點變換的次數也可以更少一些。
注意,三角形帶圖元的繪製過程,頂點並不是按照它們的指定順序進行遍歷的,這是爲了保持每個三角形的環繞方向。
三角形帶 GL_TRIANGLE_STRIP
三角形扇 GL_TRIANGLE_FAN
使用該圖元可以創建一組圍繞一箇中心點的相連三角形。在用前三個頂點指定了第一個三角形後,後續的每個頂點和原點(即中心點)以及自身前驅的那個頂點形成了接下來的那個三角形。
三角形扇 GL_TRIANGLE_FAN
設置多邊形的顏色
顏色是以頂點爲單位指定的,而不是以多邊形爲單位。着色模式決定了多邊形是單調着色(最後一個頂點的顏色作爲整個多邊形的填充顏色),或是漸變着色(根據每個頂點的顏色進行平滑着色)。
着色模式的設置函數爲:
glShadeModel(GL_FLAT);
參數GL_FLAT表示使用單調着色;
參數GL_SMOOTH表示使用平滑着色,根據每個頂點的顏色對三角形進行漸變着色,對相鄰頂點的顏色進行勻和。
深度測試
這是一種有效地用於隱藏表面消除的技巧,它的概念十分簡單:當一個像素被繪製時,它將被設置一個深度值(稱爲Z值),以表示它和觀察者之間的距離。以後,當這個屏幕位置需要繪製另一個像素時,新像素的Z值就會與原先已經存儲的那個像素進行比較。如果新像素的Z值更高,它就更靠近觀察者,因此位於以前那個像素的前面;如果新像素的Z值更低,則它必須位於原先那個像素的後面,而不能遮住前面的那個像素。在OpenGL內部,這個任務是通過深度緩衝區實現的,它存儲了屏幕上每個像素的深度值。
爲了啓用深度測試,需要調用函數:
glEnable(GL_DEPTH_TEST);
注意,每次當場景被渲染時,深度緩衝區必須被消除。
剔除(CULL)
這種技巧,用於消除已經知道肯定不會被顯示的幾何圖形。如果不向OpenGL驅動程序和硬件發送這個幾何圖形,就可以獲得顯著的性能提升。在這裏我們使用背面剔除,它用於消除一個表面的背面。
通過消除多邊形的背面,可以大幅度的減少圖像渲染所需要的處理時間。雖然深度測試可以防止物體的內表面被顯示,但OpenGL在內部還是要考慮它們,除非顯示地告訴它無須如此。
啓用背面剔除,需要調用函數:
glEnable(GL_CULL_FACE);
下面是程序清單3_8,在3D空間中繪製三角形的代碼。我們繪製了一個由三角形組合而成的圓錐,它分爲側面與底面兩大部分。該部分代碼與繪製其他圖元的代碼差別主要體現在RenderScene函數上,因此只列出了該函數部分,其餘部分代碼可參考之前的程序清單。其中使用了深度檢測與背面剔除的功能:
/* 程序清單 3-8
* 2014/4/13
*/
// 設置渲染狀態
void SetupRC()
{
// 設置清除窗口的顏色(黑色背景)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 設置繪圖顏色爲綠色
glColor3f(0.0f, 1.0f, 0.0f);
// 把着色模式設置爲單調着色
glShadeModel(GL_FLAT);
// 把順時針環繞的多邊形設爲正面,這與默認是相反的,因爲我們使用的是三角形扇
glFrontFace(GL_CW);
}
// 繪製場景(顯示回調函數)
void RenderScene()
{
// 存儲座標和角度
GLfloat x, y, z, angle;
// 用於三角形顏色的交替設置
int iPivot= 1;
// OpenGL命令,清除顏色緩衝區(使用當前設置的顏色)和
// 深度緩衝區(每次繪製場景必須清除)
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);
// 打開剔除功能(背面剔除,它用於消除一個表面的背面)
glEnable(GL_CULL_FACE);
// 打開深度測試
glEnable(GL_DEPTH_TEST);
// 保存矩陣狀態並旋轉
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// 開始繪製圖元-三角形扇
glBegin(GL_TRIANGLE_FAN);
// 三角形扇的共享頂點,作爲圓錐的錐尖,沿Z軸移動,產生一個圓錐
glVertex3f(0.0f, 0.0f, 75.0f);
// 繞一個圓循環,指定三角形扇的頂點
for (angle= 0.0f; angle <= (2.0f * GL_PI + GL_PI / 8.0f); angle += (GL_PI / 8.0f)) {
// 計算下一個頂點的位置
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
// 交替使用紅色和綠色
if((iPivot % 2) == 0) {
glColor3f(0.0f, 1.0f, 0.0f);
} else{
glColor3f(1.0f, 0.0f, 0.0f);
}
// 增加基準值,下次改變顏色
++iPivot;
// 爲三角形扇指定下一個頂點
glVertex2f(x, y);
}
glEnd();
// 繪製一個新的三角形扇,作爲覆蓋圓錐的底
glBegin(GL_TRIANGLE_FAN);
// 三角形扇的共享頂點,中心位於原點
glVertex2f(0.0f, 0.0f);
//
for (angle= 0.0f; angle < (2.0f * GL_PI + GL_PI / 8.0f); angle += (GL_PI / 8.0f)) {
// 計算下一個頂點的位置
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
// 交替使用綠色和藍色
if((iPivot % 2) == 0) {
glColor3f(0.0f, 1.0f, 0.0f);
} else{
glColor3f(0.0f, 0.0f, 1.0f);
}
// 增加基準值,下次改變顏色
++iPivot;
// 指定三角形扇的下一個頂點
glVertex2f(x, y);
}
glEnd();
// 恢復矩陣狀態
glPopMatrix();
// 刷新繪圖命令,此時所有未執行的OpenGL命令被執行
glutSwapBuffers();
}
程序運行的結果如圖所示,我們可以清楚地看到背面剔除的效果(圓錐底面的正面朝向了圓錐內部):