OpenGL(二)圖形繪製之平面多面體的繪製
通過繪製一個三菱錐初步瞭解繪製平面多面體。
<span style="font-size:18px;">#include<windows.h> #include<gl/gl.h> #include<gl/glut.h> #include<gl/glu.h> #include<stdio.h> //視窗的大小 GLsizei windowWidth; GLsizei windowHeight; //旋轉角度引數 static GLfloat xRot = 0.0f; static GLfloat yRot = 0.0f; //確定多邊形的繞法的方向 BOOL bDepth = FALSE; //深度測試開關 BOOL bCull = FALSE; //剔除開關 //初始化視窗 void SetupRC(void) { //設定視窗背景西顏色為黑色 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //指定多變形的陰影模式為平面陰暗模式 glShadeModel(GL_FLAT); } void ChangeSize(int w, int h) { if (h == 0) h = 1; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) { glOrtho(-100.0f, 100.0f, -100.0f*h / w, 100.0f*h / w, -100.0f, 100.0f); } else { glOrtho(-100.0f*w / h, 100.0f*w / h, -100.0f, 100.0f, -100.0f, 100.0f); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void RenderScene(void) { //清除顏色及深度緩衝區 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //是否開啟設度模式 if (bDepth) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); //是否開啟剔除 if (bCull) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); //旋轉圖形 glPushMatrix(); //角度正負決定是順逆時針 glRotatef(xRot,1.0f,0.0f,0.0f); //使整個場景繞著x軸旋轉 glRotatef(yRot, 0.0, 1.0, 0.0f);//使整個場景繞著y軸旋轉 //指定順時針繞法的多變形為正多變邊形正面 //glFrontFace(GL_CW); //繪製三菱錐的三個稜面 //他們的顏色分別為紅、綠、藍 glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0, 0.0,80); glVertex3f(0.0, 50.0,0.0); glColor3f(1.0,0.0,0.0); //紅色 glVertex3f(50.0,-50.0,0.0); glColor3f(0.0f, 1.0f, 0.0); //綠色 glVertex3f(-50.0,-50.0,0.0); glColor3f(0.0f,0.0f,1.0f); //藍色 glVertex3f(0.0,50.0,0.0); glEnd(); //繪製三菱錐的地面,其顏色為黃色 glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0,50.0,0.0); glVertex3f(50.0,-50.0,0.0); glColor3f(1.0,1.0,0.0); //黃色 glVertex3f(-50.0,-50.0,0.0); glEnd(); glPopMatrix(); glutSwapBuffers(); //重新整理命令緩衝區 } void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) xRot -= 5.0f; if (key == GLUT_KEY_DOWN) xRot += 5.0f; if (key == GLUT_KEY_LEFT) yRot -= 5.0f; if (key == GLUT_KEY_RIGHT) yRot += 5.0f; //結合glPushMatrix()和glPopMatrix()繪圖模式理解旋轉 // 首先,glPushMateix記住來的繪圖座標(起點) //glRotatef(xRot, 1.0f, 0.0f, 0.0f); //glRotatef(yRot, 0.0f, 1.0f, 0.0f); //然後旋轉相應的座標後繪製圖形 //glPopMatrix 回到了座標原來的位置(起點) printf("%lf\n", yRot); if (xRot >= 360.0f) xRot = 0.0f; if (xRot < -1.0f) xRot=355.0f; if (yRot >= 360.0f) yRot = 0.0f; if (yRot < -1.0f) yRot = 355.0f; //重新整理視窗 強制 glutPostRedisplay(); } void ProcessMenu(int value) { switch (value) { case 1:bDepth = !bDepth; break; case 2:bCull = !bCull; break; default: break; } //強制重新整理 glutPostRedisplay(); } int main(int argc, char *argv[]) { //initialize the GLUT library //初始化GLUT庫 glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("三菱錐"); //回撥函式 glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); //設定特殊鍵盤相應回撥函式 glutSpecialFunc(SpecialKeys); //void glutSpecialFunc(void(*func)(int key,int x,int y)); //special函式第一個關鍵字是鍵盤的值, x,y是獲取滑鼠點選的座標 // sets the special keyboard callback for the current window //the special keyboared callback is triggered when keyboard function or //directional keys are pressed //建立一個選單 glutCreateMenu(ProcessMenu); glutAddMenuEntry("深度測試",1); glutAddMenuEntry("剔除背面",2); glutAttachMenu(GLUT_RIGHT_BUTTON); SetupRC(); glutMainLoop(); return 0; } </span>
程式一開始執行的圖片結果如下:
通過旋轉和使用深度測試功能結果如下:
本次學習知識點:
在旋轉的過程中,紅色的稜鏡始終不能顯示出來,這是因為紅色的稜面是最先繪製的,它總是被後面繪製的綠色,藍色或黃色的多邊形所遮擋,要改變這種狀況就需要啟用深度測試。
1. 深度測試 (恢復看不到的區域)
在繪製圖形的過程中,有時一個物體的一部分會被其前方的物體擋住(從觀察者的角度看),如果這是這個物體在檔在其前面的物體繪製完成之後繪製,那麼螢幕中顯示的圖形將不是我們所希望的,即後面的物體擋住了前面的物體。
只需啟用一項稱為深度測試的功能就可以解決這一問題。
啟動深度測試: 呼叫 glEnable(GL_DEPTH_TEST);
關閉深度測試: 呼叫 glDisable(GL_DEPTH_TEST);
深度測試是一種移除被擋住表面的有效技術,它的過程是:在繪製一個畫素時,會給他分配一個值(稱為z值),這個值表示它與觀察者的距離。然後,如果需要在同一個位置上繪製另一個畫素,將比較新畫素和已經儲存的該位置的畫素的z值。如果新畫素的z的值比較大,即它離觀察者更近因而在原來那個畫素的前面,原來的畫素就會被新畫素擋住。這一操作在內部有深度緩衝區完成。
為了使深度緩衝區正常完成深度測試功能,每次渲染場景時,必須先清除深度緩衝區:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
2.隱藏表面
啟用深度測試之後,我們得到良好的視覺效果,但是還是付出了一些效能代價,因為每個畫出的畫素都必須與先前畫素的z值比較。但是如果我們知道某些表面無論如何也不必畫出,我們可以將其指出,這種技術稱為"剔除",這種技術可以將已知永遠看不到的幾何圖形消除掉,這樣可以顯著的改善效能。
那麼哪些表面時永遠看不到的呢?最常見的例子就是封閉物體的內部表面。一種稱為回溯的技術可以消除表面的背面,通過
glEnable/glDisable(GL_CULL_FACE)
來實現。啟用剔除技術後,我們發現三稜錐的底面消失了,這是因為在繪製的過程中,我們都使用了順時針繞法的多邊形正面,但這樣底面的正面正對著三稜錐的內部,故此啟用剔除技術後把底面剔出掉了,要改變這種狀況,可以在繪製三稜錐的底面前呼叫函式
glFrontFace(GL_CCW);