1.實驗目的:
理解基本圖形元素光柵化的基本原理,掌握一種基本圖形元素光柵化算法,利用OpenGL實現直線光柵化的DDA算法。
2.實驗內容:
(1) 根據所給的直線光柵化的示范源程序,在計算機上編譯運行,輸出正確結果;
(2) 指出示范程序采用的算法,以此為基礎將其改造為中點線算法或Bresenham算法,寫入實驗報告;
(3) 根據示范代碼,將其改造為圓的光柵化算法,寫入實驗報告;
(4) 了解和使用OpenGL的生成直線的命令,來驗證程序運行結果。
3.實驗原理:
示范代碼原理參見教材直線光柵化一節中的DDA算法。下面介紹下OpenGL畫線的一些基礎知識和glutReshapeFunc()函數。
(1)數學上的直線沒有寬度,但OpenGL的直線則是有寬度的。同時,OpenGL的直線必須是有限長度,而不是像數學概念那樣是無限的。可以認為,OpenGL的“直線”概念與數學上的“線段”接近,它可以由兩個端點來確定。這里的線由一系列頂點順次連結而成,有閉合和不閉合兩種。
前面的實驗已經知道如何繪“點”,那么OpenGL是如何知道拿這些頂點來做什么呢?是一個一個的畫出來,還是連成線?或者構成一個多邊形?或是做其它事情呢?為了解決這一問題,OpenGL要求:指定頂點的命令必須包含在glBegin函數之后,glEnd函數之前(否則指定的頂點將被忽略),並由glBegin來指明如何使用這些點。
例如:
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();
則這兩個點將分別被畫出來。如果將GL_POINTS替換成GL_LINES,則兩個點將被認為是直線的兩個端點,OpenGL將會畫出一條直線。還可以指定更多的頂點,然后畫出更復雜的圖形。另一方面,glBegin支持的方式除了GL_POINTS和GL_LINES,還有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每種方式的大致效果如圖A.2所示:
圖A.2 OpenGL幾何圖元類型
(2)首次打開窗口、移動窗口和改變窗口大小時,窗口系統都將發送一個事件,以通知程序員。如果使用的是GLUT,通知將自動完成,並調用向glutReshapeFunc()注冊的函數。該函數必須完成下列工作:
Ÿ 重新建立用作新渲染畫布的矩形區域;
Ÿ 定義繪制物體時使用的坐標系。
如:
void Reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
}
在GLUT內部,將給該函數傳遞兩個參數:窗口被移動或修改大小后的寬度和高度,單位為像素。glViewport()調整像素矩形,用於繪制整個窗口。接下來三個函數調整繪圖坐標系,使左下角位置為(0, 0),右上角為(w, h)。
4.實驗代碼:
1 #include <GL/glut.h> 2 3 void LineDDA(int x0,int y0,int x1,int y1/*,int color*/) 4 5 { 6 7 int x, dy, dx, y; 8 9 float m; 10 11 dx=x1-x0; 12 13 dy=y1-y0; 14 15 m=dy/dx; 16 17 y=y0; 18 19 glColor3f (1.0f, 1.0f, 0.0f); 20 21 glPointSize(1); 22 23 for(x=x0;x<=x1; x++) 24 25 { 26 27 glBegin (GL_POINTS); 28 29 glVertex2i (x, (int)(y+0.5)); 30 31 glEnd (); 32 33 y+=m; 34 35 } 36 37 } 38 39 void myDisplay(void) 40 41 { 42 43 glClear(GL_COLOR_BUFFER_BIT); 44 45 glColor3f (1.0f, 0.0f, 0.0f); 46 47 glRectf(25.0, 25.0, 75.0, 75.0); 48 49 glPointSize(5); 50 51 glBegin (GL_POINTS); 52 53 glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.0f, 0.0f); 54 55 glEnd (); 56 57 LineDDA(0, 0, 200, 300); 58 59 glBegin (GL_LINES); 60 61 glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (100.0f, 0.0f); 62 63 glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (180.0f, 240.0f); 64 65 glEnd (); 66 67 glFlush(); 68 69 } 70 71 void Init() 72 73 { 74 75 glClearColor(0.0, 0.0, 0.0, 0.0); 76 77 glShadeModel(GL_FLAT); 78 79 } 80 81 void Reshape(int w, int h) 82 83 { 84 85 glViewport(0, 0, (GLsizei) w, (GLsizei) h); 86 87 glMatrixMode(GL_PROJECTION); 88 89 glLoadIdentity(); 90 91 gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h); 92 93 } 94 95 int main(int argc, char *argv[]) 96 97 { 98 99 glutInit(&argc, argv); 100 101 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); 102 103 glutInitWindowPosition(100, 100); 104 105 glutInitWindowSize(400, 400); 106 107 glutCreateWindow("Hello World!"); 108 109 Init(); 110 111 glutDisplayFunc(myDisplay); 112 113 glutReshapeFunc(Reshape); 114 115 glutMainLoop(); 116 117 return 0; 118 119 }
注: glShadeModel選擇平坦或光滑漸變模式。GL_SMOOTH為缺省值,為光滑漸變模式,GL_FLAT為平坦漸變模式。
5.實驗提高
示范代碼有個小錯誤,能否指出並改正?請將結果寫入實驗報告。
附: 本實驗的VC++工程代碼(VC++2008)

