實驗預備知識
Windows下的OpenGL編程步驟簡單介紹詳見課程實驗教學博客-實驗准備安裝GLUT包與創建工程:
http://www.cnblogs.com/opengl/archive/2012/10/16/2726747.html
1.實驗目的:
熟悉編程環境;了解光柵圖形顯示器的特點;了解計算機繪圖的特點;利用VC+OpenGL作為開發平台設計程序,以能夠在屏幕上生成任意一個像素點為本實驗的結束。
2.實驗內容:
(1) 了解和使用VC的開發環境,理解簡單的OpenGL程序結構。
(2) 掌握OpenGL提供的基本圖形函數,尤其是生成點的函數。
3.實驗原理:
(1)基本語法
常用的程序設計語言,如C、C++、Pascal、Fortran和Java等,都支持OpenGL的開發。這里只討論C版本下OpenGL的語法。
OpenGL基本函數均使用gl作為函數名的前綴,如glClearColor();實用函數則使用glu作為函數名的前綴,如gluSphere()。OpenGL基本常量的名字以GL_開頭,如GL_LINE_LOOP;實用常量的名字以GLU_開頭,如GLU_FILL。一些函數如glColor*()(定義顏色值),函數名后可以接不同的后綴以支持不同的數據類型和格式。如glColor3b(...)、glColor3d(...)、glColor3f(...)和glColor3bv(...)等,這幾個函數在功能上是相似的,只是適用於不同的數據類型和格式,其中3表示該函數帶有三個參數,b、d、f分別表示參數的類型是字節型、雙精度浮點型和單精度浮點型,v則表示這些參數是以向量形式出現的。
為便於移植,OpenGL定義了一些自己的數據類型,如GLfloat,GLvoid。它們其實就是C中的float和void。在gl.h文件中可以看到以下定義:
……
typedef float GLfloat;
typedef void GLvoid;
……
一些基本的數據類型都有類似的定義項。
(2)程序的基本結構
OpenGL程序的基本結構可分為三個部分:
第一部分是初始化部分。主要是設置一些OpenGL的狀態開關,如顏色模式(RGBA或Alpha)的選擇,是否作光照處理(若有的話,還需設置光源的特性),深度檢測,裁剪等等。這些狀態一般都用函數glEnable(...), glDisable(…)來設置,…表示特定的狀態。
第二部分設置觀察坐標系下的取景模式和取景框位置大小。主要利用了三個函數:
函數void glViewport(left,top,right,bottom):設置在屏幕上的窗口大小,四個參數描述屏幕窗口四個角上的坐標(以像素表示);
函數void glOrtho(left,right,bottom,top,near,far):設置投影方式為正交投影(平行投影),其取景體積是一個各面均為矩形的六面體;
函數void gluPerspective(fovy,aspect,zNear,zFar):設置投影方式為透視投影,其取景體積是一個截頭錐體。
第三部分是OpenGL的主要部分,使用OpenGL的庫函數構造幾何物體對象的數學描述,包括點線面的位置和拓撲關系、幾何變換、光照處理等等。
以上三個部分是OpenGL程序的基本框架,即使移植到使用MFC的Windows程序中,也是如此。只是由於Windows自身有一套顯示方式,需要進行一些必要的改動以協調這兩種不同顯示方式。
(3)狀態機制
OpenGL的工作方式是一種狀態機制,它可以進行各種狀態或模式設置,這些狀態或模式在重新改變它們之前一直有效。例如,當前顏色就是一個狀態變量,在這個狀態改變之前,繪制的每個像素都將使用該顏色,直到當前顏色被設置為其它顏色為止。OpenGL中大量地使用了這種狀態機制,如顏色模式、投影模式、單雙顯示緩存區的設置、背景色的設置、光源的位置和特性等等。許多狀態變量可以通過glEnable()、glDisable()這兩個函數來設置成有效或無效狀態,如是否設置光照、是否進行深度檢測等;在被設置成有效狀態之后,絕大部分狀態變量都有一個缺省值。通常情況下,可以用下列四個函數來獲取某個狀態變量的值:glGetBooleanv()、glGetDouble()、glGetFloatv()和glGetIntegerv()。究竟選擇哪個函數應該根據所要獲得的返回值的數據類型來決定。還有些狀態變量有特殊的查詢函數,如glGetLight*()、glGetError()和glPolygonStipple()等。另外,使用glPushAttrib()和glPopAttrib()函數,可以存儲和恢復最近的狀態變量的值。只要有可能,都應該使用這些函數,因為它們比其它查詢函數的效率更高。
4.實驗代碼:
1 #include <GL/glut.h> //需要正確安裝GLUT,安裝方法如預備知識中所述 2 3 void myDisplay(void) 4 5 { 6 7 glClearColor(0.0, 0.0, 0.0, 0.0); 8 glClear(GL_COLOR_BUFFER_BIT); 9 10 glColor3f (1.0f, 1.0f, 1.0f); 11 12 glRectf(-0.5f, -0.5f, 0.5f, 0.5f); 13 14 glBegin (GL_TRIANGLES); 15 16 glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (0.0f, 1.0f); 17 18 glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.8f, -0.5f); 19 20 glColor3f (0.0f, 0.0f, 1.0f); glVertex2f (-0.8f, -0.5f); 21 22 glEnd (); 23 24 glPointSize(3); 25 26 glBegin (GL_POINTS); 27 28 glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (-0.4f, -0.4f); 29 30 glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.0f, 0.0f); 31 32 glColor3f (0.0f, 0.0f, 1.0f); glVertex2f (0.4f, 0.4f); 33 34 glEnd (); 35 36 glFlush(); 37 } 38 int main(int argc, char *argv[]) 39 { 40 glutInit(&argc, argv); 41 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); 42 glutInitWindowPosition(100, 100); 43 glutInitWindowSize(400, 400); 44 glutCreateWindow("Hello World!"); 45 glutDisplayFunc(&myDisplay); 46 glutMainLoop(); 47 return 0; 48 }
該程序的作用是在一個黑色的窗口中央畫一個矩形、三角形和三個點,如圖A.1(a)所示。下面對各行語句進行說明:
首先,需要包含頭文件#include <GL/glut.h>,這是GLUT的頭文件。本來OpenGL程序一般還要包含<GL/gl.h>和<GL/glu.h>,但GLUT的頭文件中已經自動將這兩個文件包含了,不必再次包含;
然后看main函數。int main(int argc, char *argv[]),這個是帶命令行參數的main函數。注意main函數中的各語句,除了最后的return之外,其余全部以glut開頭。這種以glut開頭的函數都是GLUT工具包所提供的函數,下面對用到的幾個函數進行介紹;
1)glutInit,對GLUT進行初始化,這個函數必須在其它的GLUT使用之前調用一次。其格式比較固定,一般都是glutInit(&argc, argv)就行;
2) glutInitDisplayMode,設置顯示方式,其中GLUT_RGB表示使用RGB顏色,與之對應的還有GLUT_INDEX(表示使用索引顏色)。GLUT_SINGLE表示使用單緩沖,與之對應的還有GLUT_DOUBLE(使用雙緩沖)。更多信息,以后的實驗教程會有講解介紹;
3) glutInitWindowPosition,設置窗口在屏幕中的位置;
4) glutInitWindowSize,設置窗口的大小;
5) glutCreateWindow,根據前述設置的信息創建窗口。參數將被作為窗口的標題。注意:窗口被創建后,並不立即顯示到屏幕上。需要調用glutMainLoop才能看到窗口;
6) glutDisplayFunc,設置一個函數,當需要進行畫圖時,這個函數就會被調用。(暫且這樣理解);
7) glutMainLoop,進行一個消息循環。(現在只需知道這個函數可以顯示窗口,並且等待窗口關閉后才會返回。)
在glutDisplayFunc函數中,我們設置了“當需要畫圖時,請調用myDisplay函數”。於是myDisplay函數就用來畫圖。觀察myDisplay中的三個函數調用,發現它們都以gl開頭。這種以gl開頭的函數都是OpenGL的標准函數,下面對用到的函數進行介紹:
1) glClearColor(0.0, 0.0, 0.0, 0.0) :將清空顏色設為黑色(為什么會有四個參數?);
2) glClear(GL_COLOR_BUFFER_BIT):將窗口的背景設置為當前清空顏色;
3) glRectf,畫一個矩形。四個參數分別表示了位於對角線上的兩個點的橫、縱坐標;
4) glFlush,保證前面的OpenGL命令立即執行(而不是讓它們在緩沖區中等待)。
5. 實驗提高
(a)示范程序結果 (b)加三角形
圖A.1實驗1
如圖A.1(b)所示,根據示范程序,能否在原有結果基礎上添加三條直線組成三角形?
附上本實驗的VC++工程代碼(VC++2008)