400 likes | 673 Vues
Introduction to OpenGL (2). 靜宜大學資工系 蔡奇偉 副教授 2001-2008. Red Book 第二章. 大綱. OpenGL 的命名慣例 OpenGL/GLUT hello 程式 清除視窗的內容 設定目前的繪圖顏色 glFlush() 與 glFinish() OpenGL 的基本幾何元件 設定 / 讀取 OpenGL 的狀態 設定圖形的屬性. OpenGL 的命名慣例. 函式名稱以 gl 開頭,而且名稱中每個字的字首使用大寫,如 glClearColor() 。
E N D
Introduction to OpenGL (2) 靜宜大學資工系 蔡奇偉 副教授 2001-2008 Red Book 第二章
大綱 • OpenGL 的命名慣例 • OpenGL/GLUT hello 程式 • 清除視窗的內容 • 設定目前的繪圖顏色 • glFlush() 與 glFinish() • OpenGL 的基本幾何元件 • 設定/讀取 OpenGL 的狀態 • 設定圖形的屬性
OpenGL 的命名慣例 • 函式名稱以 gl 開頭,而且名稱中每個字的字首使用大寫,如 glClearColor()。 • 常數名稱全為大寫字母並以 GL 開頭,名稱中每個字用底線字元(_) 隔開,如 GL_COLOR_BUFFER_BIT。 • 某些函式的字尾暗示參數的個數與型態,如glVertex3f (float x, float y, float z) /* 3 個浮點數 */ • glVertex2i (int x, int y) /* 2 個整數 */ • glVetex3fv (float *vl) /* 3 個浮點數組成的陣列 */
字尾 資料型態 OpenGL 資料型態 b signed char GLbyte s short GLshort i int (or long) GLint, GLsizei f float GLfloat, GLclampf d double GLdouble, GLclampd ub unsigned char GLubyte, GLboolean us unsigned short GLushort ui unsigned int GLuint, GLenum, GLbitfield (or unsigned long) 此外,參數為陣列的函式通常以字母 v 為結尾。
OpenGL/GLUT hello 程式 • hello.c 原始碼 • GLUT 初始化函式 • 事件驅動程式 • GLUT callback 函式 • GLUT mainloop 函式
/* * hello.c * This is a simple, introductory OpenGL program. */ #include <GL/glut.h>
void display(void) { glClear (GL_COLOR_BUFFER_BIT); /* clear all pixels */ /* draw white polygon (rectangle) with corners at * (0.25, 0.25, 0.0) and (0.75, 0.75, 0.0) */ glColor3f (1.0, 1.0, 1.0); glBegin(GL_POLYGON); glVertex3f (0.25, 0.25, 0.0); glVertex3f (0.75, 0.25, 0.0); glVertex3f (0.75, 0.75, 0.0); glVertex3f (0.25, 0.75, 0.0); glEnd(); /* don't wait! * start processing buffered OpenGL routines */ glFlush (); }
void init (void) { /* select clearing color */ glClearColor (0.0, 0.0, 0.0, 0.0); /* initialize viewing values */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); }
/* * Declare initial window size, position, and display mode * (single buffer and RGBA). Open window with "hello" * in its title bar. Call initialization routines. * Register callback function to display graphics. * Enter main loop and process events. */ int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow ("hello"); init (); glutDisplayFunc(display); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }
GLUT 初始化函式 • glutInit (int *argc, char ** argv) • 設定啟動 GLUT 所需的初值,然後處理一些指令行的參數(用於 X Window 系統)。呼叫這個函式後才能夠開始呼叫其他的 GLUT 函式。
glutInitDisplayMode (unsigned int mode) • 設定顯示的模式。你可以用 bitwise OR(|)的方式來選取以下的模式 : • GLUT_RGBA(或 GLUT_RGB), GLUT_INDEX • GLUT_SINGLE, GLUT_DOUBLE • GLUT_ACCUM • GLUT_ALPHA • GLUT_DEPTH • GLUT_STENCIL • GLUT_LUMINANCE
glutInitWindowSize (int width, int height) 設定視窗的初始大小為 width x height像素。 glutInitWindowPosition (int x, int y) 設定視窗在螢幕上的初始位置為 (x, y) 像素。 glutCreateWindow (char *name) 建立和顯示最上層的視窗並把視窗的標題設成 name。
事件驅動程式 目前流行的視窗系統(如 X Window、MS Windows)是採用事件驅動(event-driven)的模式。視窗系統必須處理許多不同的事件(event)— 如:鍵盤輸入、滑鼠移動、壓下滑鼠按鍵、放開滑鼠按鍵等等使用者的動作,以及視窗遮蓋、視窗浮現等等螢幕狀態的改變。這些事件依序地擺放在所謂的事件佇列(event queue)中,然後用循覆的方式依序處理(稱為事件迴路(event loop))。我們以下圖說明之:
front rear 加入新事件 event queue 取出下一個事件 event loop 判斷是何事件 呼叫該事件的 處理函式
GLUT callback 函式 • GLUT 利用 callback 函式的機制來註冊事件處理函式。GLUT 提供了一些函式來設定事件處理函式。 • glutDisplayFunc (void (*func)(void)) • 設定 func為處理視窗內容變動事件的函式。我們必須把所有繪製視窗內容的程式碼寫在函式 func 之中。
glutReshapeFunc (void (*func)(int w, int h)) • 設定 func為處理視窗大小變動事件的函式。參數 w和 h是視窗的新寬度與新高度。 • glutKeyboardFunc (void (*func)(unsigned char key, int x, int y)) • 設定 func為處理鍵盤事件的函式。參數 key是按鍵的 ASCII 碼,參數 (x, y) 是按鍵時滑鼠所在的座標。 • glutMouseFunc (void (*func)(int button, int x, int y)) • 設定 func為處理滑鼠按鍵事件的函式。參數 button是所按下或放開的滑鼠鍵,參數 (x, y) 是按鍵時滑鼠所在的座標。
glutMotionFunc (void (*func)(int x, int y)) • 設定 func為處理按住滑鼠鍵並移動滑鼠事件的函式。參數 x和 y是滑鼠目前所在的座標。 • glutPassiveMotionFunc (void (*func)(int x, int y)) • 設定 func為處理滑鼠移動事件(未按下滑鼠鍵)的函式。參數 x和 y是滑鼠目前所在的座標。 • glutIdleFunc (void (*func)(void)) • 設定 func為處理「空事件(即無任何事件發生)」的函式。
glutTimerFunc (insigned int msec, void (*func)(int value ), int value ) • 設定 func為處理定時器事件的函式。參數 msec是啟動定時器的間隔時間,其單位是毫秒(千分之一秒)。系統會每隔 msec 毫秒自動呼叫函式 func,並以glutTimerFunc第三個參數 value的值為其參數值。
void glutMainLoop (void) 在程式中你應該只呼叫glutMainLoop 函式一次來進入事件迴圈。這個函式的責任是不斷地檢驗事件的種類,然後呼叫你所指定的事件處理 callback 函式。此外,這個函式本身是一個無限迴圈,無法結束執行而回到主函式。
清除視窗的內容 • glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) • 設定清除的顏色。各顏色的成份值必須介於 0.0 和 1.0 之間。值愈小表示成份愈少。所以 (0.0, 0.0, 0.0, 0.0) 代表黑色、 (1.0, 1.0, 1.0, 0.0) 代表白色、 (1.0, 0.0, 0.0, 0.0)代表紅色、…、等等。第四個參數 alpha用來設定透明度。
glClear (GLbitfield mask) • 用目前的清除值來清除參數 mask所選定的緩衝區。以下的緩衝區可以用 bitwise OR 的方式來選取: • GL_COLOR_BUFFER_BIT (glClearColor) • GL_DEPTH_BUFFER_BIT (glClearDepth) • GL_ACCUM_BUFFER_BIT (glClearAccum) • GL_STENCIL_BUFFER_BIT (glClearStencil) • 註:不同的緩衝區需要用不同的函式(上表的右方)來設定清除值。
範例: • glClearColor(0.0, 0.0, 0.0, 0.0); • glClearDepth(1.0); • glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
設定目前的繪圖顏色 OpenGL 的繪圖函式並不需要指定顏色,而是利用目前所設定的繪圖顏色。目前的繪圖顏色是由 glColor*() 這一類的函式來指定,如: glColor3f (GLfloat red, GLfloat green, GLfloat blue) glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) glColor3fv(GLfloat *color_array) /* color_array has 3 elements */
glFlush() 和 glFinish() glFlush() 函式和 glFinish() 函式都會要求立刻執行之前所下達的 OpenGL 指令。兩者不同的地方在於: glFlush() 要求後就結束函式的執行,而 glFinish() 必須等到這些指令都完成後,才會結束函式的執行。 透過網路來執行的 OpenGL 程式可以運用這兩個函式來增進執行的效率。
OpenGL 的基本幾何元件 • Vertices(端點) • 由端點組成的基本圖形
Vertices(端點) • OpenGL 的幾何圖形都是由端點組成。你可以用 glVertex*()指令來設定端點的位置: • glVertex{234}{sifd}[v] (TYPE coords); • 例如: • glVertex2s(2, 3); • glVertex3d(0.0, 0.0, 3.14159); • glVertex4f(2.3, 1.2, 3.1, 2.0); • GLdouble dvect[] = {1.0, 2.0, 3.0}; • glVertex3dv(dvect);
由端點組成的基本圖形 • 我們可以用下面的結構來繪製 OpenGL 的基本圖形: • glBegin(type); • /* 一連串的 glVertex*() 的呼叫 */ • glEnd(); • 其中 glBegin 函式的參數 type用來指定所需的圖形,它的可能值與相對的圖形如底下幾頁所示。
v0 v2 v4 v1 v3 v5 GL_POINTS v0 v2 v4 v0 v2 v4 v0 v2 v4 v1 v3 v5 v1 v3 v5 v1 v3 v5 GL_LINE_LOOP GL_LINES GL_LINE_STRIP
v2 v0 v2 v4 v0 v2 v4 v1 v3 v0 v1 v3 v1 v3 v5 v5 v4 GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN v6 v5 v4 v2 v0 v4 v0 v7 v4 v0 v2 v5 v1 v3 v5 v7 v1 v6 v2 v3 v1 v3 GL_QUADS GL_QUADS_STRIP GL_POLYGON
指令名稱 用途 glVertex*() 設定端點的座標 glColor*() 設定目前的繪圖顏色 glIndex*() 設定目前的繪圖索引色 glNormal*() 設定端點的法向量 glTexCoord*() 設定貼圖座標 glMultiTexCoord*ARB() 設定多重貼圖座標 glEdgeFlag*() 控制端線的繪製方式 glMaterial*() 設定材質的屬性 glArrayElement() 取出端點陣列的資料 glEvalCoord*(), glEvalPoint*() 産生座標值 glCallList(), glCallLists() 執行 display list(s) glBegin() 和 glEnd() 之間只可以擺下列的 OpenGL 指令:
設定/讀取 OpenGL 的狀態 • OpenGL 用一些內部的狀態變數(state variables)來開啟或關閉若干的高級高能。 • void glEnable (GLenum cap) • 開啟參數 cap 所代表的功能。 • void glDisable (GLenum cap) • 關閉參數 cap 所代表的功能。 • GLboolean glIsEnable (GLenum cap) • 檢驗cap 所代表的功能是否已經開啟。
若要取出狀態變數的值,我們可以依據其資料型態使用下列適當的函式:若要取出狀態變數的值,我們可以依據其資料型態使用下列適當的函式: • void glGetBooleanv (Glenum pname, GLboolean *params) • void glGetIntegerv (Glenum pname, GLint *params) • void glGetFloatv (Glenum pname, GLfloat *params) • void glGetDoublev (Glenum pname, GLdouble *params) • void glGetPointerv (Glenum pname, GLvoid *params) • 其中的第一個參數是狀態變數的符號名稱,如 GL_CURRENT_COLOR 代表儲存目前繪圖顏色的狀態變數。所以, • GLint params[4]; • glGetIntegerv (GL_CURRENT_COLOR, params); • 把目前的繪圖顏色取出存放在陣列 params 中。
設定圖形的屬性 • glPointSize() • glLineWidth() • glLineStipple()
default antialiasing void glPointSize (GLfloat size) 設定端點的像素大小(預設值是 1.0)。參數 size不可以代入 0.0。端點有兩種顯示形狀:在預設的情況下, size 先被四捨五入成整數 n,然後端點被畫成 nn個像素的方點。若啟動平滑功能(antialiasing)的話, size 不會被四捨五入,而且端點被畫成近似圓的點。
啟動平滑繪點的功能: • glEnable(GL_POINT_SMOOTH); • 你可以用下列參數代入函式 glGetFloatv() 及來查詢 OpneGL 系統的能力: • GL_ALIASED_POINT_SIZE_RANGE • 點大小的允許範圍 • GL_SMOOTH_POINT_SIZE_RANGE • 平滑點大小的允許範圍 • GL_SMOOTH_POINT_SIZE_GRANULARITY • 平滑點大小的精確度
glLineWidth(GLfloat width) 設定線段的寛度(預設值是 1.0 個像素)。同端點一樣,反鋸齒的平滑功能是否啟動會影響到線段的繪製方式。在預設的情況下, width 先被四捨五入成整數 n。斜率小於 1 的線,垂直厚度設為 n個像素,斜率大於 1 的線,則水平厚度設為 n個像素。若啟動平滑功能,則 width 不會被四捨五入成整數 n,同時線段的周圍用較暗的像素來達成平滑的效果。
平滑 line width = 2 非平滑 line width = 2
啟動平滑繪線的功能: • glEnable(GL_LINE_SMOOTH); • 你可以用下列參數代入函式 glGetFloatv() 及來查詢 OpneGL 系統的能力: • GL_ALIASED_LINE_WIDTH_RANGE • 線寛度大小的允許範圍 • GL_SMOOTH_LINE_WIDTH_RANGE • 平滑線寛度的允許範圍 • GL_SMOOTH_LINE_WIDTH_GRANULARITY • 平滑線寛度的精確度
Pattern 十六進位 factor 樣式 0000000011111111 0x00FF 1 0000000011111111 0x00FF 2 0000110000001111 0x0C0F 1 1010101010101010 0xAAAA 1 glLineStipple(GLint factor, GLushort pattern) 這個函式可用來設定線段的樣式。使用這個函式之前,你必須呼叫 glEnable(GL_LINE_STIPPLE)來啟動這個功能。參數 pattern是一個 16-bit 的整數,用來定義線段的樣式,其中的 bits 由右至左地檢視,若為 1,則表示要畫點,若為 0 的話,則表示不要畫點。參數 factor控制樣式的放大倍數。