Hướng dẫn lập trình OpenGL căn bản

1.1. Xóa màn hình

Trong OpenGL có 2 loại buffer phổ biến nhất

 color buffer: buffer chứa màu của các pixel cần được thể hiện

 depth buffer (hay còn gọi là z-buffer): buffer chứa chiều sâu của pixel, được đo bằng

khoảng cách đến mắt. Mục đích chính của buffer này là loại bỏ phần đối tượng nằm sau

đối tượng khác.

Mỗi lần vẽ, chúng ta nên xóa buffer

glClearColor(0.0, 0.0, 0.0, 0.0); /* xác định màu để xóa color buffer

(màu đen) */

glClearDepth(1.0); /* xác định giá trị để xóa depth buffer */

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* xóa color

buffer và depth buffer */

1.2. Xác định màu

Khi vẽ một đối tượng, OpenGL sẽ tự động sử dụng màu đã được xác định trước đó. Do đó, để vẽ

đối tượng với màu sắc theo ý mình, cần phải thiết lập lại màu vẽ. Thiết lập màu vẽ mới dùng

hàm glColor3f(), ví dụ

glColor3f(0.0, 0.0, 0.0); // black

glColor3f(1.0, 0.0, 0.0); // red

glColor3f(0.0, 1.0, 0.0); // green

glColor3f(1.0, 1.0, 0.0); // yellow

glColor3f(0.0, 0.0, 1.0); // blue

glColor3f(1.0, 0.0, 1.0); // magenta

glColor3f(0.0, 1.0, 1.0); // cyan

glColor3f(1.0, 1.0, 1.0); // white

pdf33 trang | Chuyên mục: Đồ Họa Máy Tính | Chia sẻ: tuando | Lượt xem: 379 | Lượt tải: 0download
Tóm tắt nội dung Hướng dẫn lập trình OpenGL căn bản, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
g đoạn lớn chúng ta cần phải làm 
1) Thực hiện các thao tác vẽ trong chế độ render (đây là điều mà 4 chương trước đã bàn tới) 
2) Thực hiện các thao tác vẽ trong chế độ selection (giống hoàn toàn như trong công đoạn 
1), kết hợp với một số thao tác đặc trưng trong chế độ selection. 
Công đoạn 1 là các thao tác để biến đổi các đối tượng trong không gian về các pixel và sau đó 
hiển thị lên màn hình. Công đoạn 2, gần như ngược lại, chương trình xác định xem pixel mà 
người dùng tương tác (ví dụ như nhấn chuột trái) thuộc đối tượng nào. 
Để chuyển đổi qua lại giữa các công đoạn (hay chế độ), chúng ta dùng hàm 
GLint glRenderMode(GLenum mode); 
trong đó mode là GL_RENDER hoặc GL_SELECT (mode còn có thể là GL_FEEDBACK nhưng ở đây 
chúng ta sẽ không xét tới). 
2. Các thao tác trên chế độ selection 
Trước tiên chúng ta cần kích hoạt chế độ selection 
glRenderMode(GL_SELECT) 
2.1. Xác định vùng chọn 
Ví dụ về chọn đối tượng bằng click chuột được cho như hình dưới đây 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 27 
Việc xác định vùng chọn tương tự như là việc xác định khối nhìn, tức là chúng ta sẽ thao tác trên 
phép chiếu (projection – chương 3, mục 3). 
Thao tác tổng quát như sau 
glMatrixMode (GL_PROJECTION); 
glPushMatrix (); 
glLoadIdentity (); 
gluPickMatrix (...); 
gluPerspective, glOrtho, gluOrtho2D, or glFrustum 
 /* ... */ 
glPopMatrix(); 
Trong đó, 
void gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble 
height, GLint viewport[4]); 
là hàm xác định vùng quan tâm trong viewport (ví dụ như xung quanh vùng click chuột) với: 
 (x, y, width, height) là tham số xác định quan tâm trên viewport 
 viewport[4] là mảng 4 phần tử chứa 4 tham số của viewport, có thể dùng hàm 
glGetIntegerv(GL_VIEWPORT, GLint *viewport) để lấy ra. 
2.2. Thiết lập đối tượng và danh tính cho đối tượng 
Để phân biệt được các đối tượng với nhau, OpenGL cần phải đặt tên cho các đối tượng cần quan 
tâm. Việc đặt tên này có 3 điều đáng lưu ý 
1) tên là một số nguyên, 
2) các đối tượng có thể mang cùng tên: đây là các đối tượng được gom vào cùng một nhóm 
được quan tâm, ví dụ như nhóm các hình cầu, nhóm các hình khối hộp, 
3) tên có thể mang tính phân cấp, thể hiện ở đối tượng được cấu thành từ nhiều thành phần 
khác nhau. Ví dụ như khi click vào một cái bánh của cái một cái xe hơi, chúng ta cần biết 
là cái bánh số mấy của cái xe hơi số mấy. 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 28 
OpenGL có một stack giúp thao tác trên tên các đối tượng, với các hàm 
 void glInitNames(void) khởi tạo stack (stack lúc này rỗng) 
 void glPushName(GLuint name) đặt tên của đối tượng cần xét vào trong stack 
 void glPopName(void) lấy tên nằm ở đỉnh stack ra khỏi stack 
 void glLoadName(GLuint name) thay nội dung của đỉnh stack 
Việc sử dụng stack này giúp cho mục đích thứ 3 – xây dựng tên mang tính phân cấp. Mỗi lần 
thực thi glPushName(name) hoặc glLoadName(name) thì chương trình sẽ hiểu là các đối tượng 
được vẽ ở các dòng lệnh sau sẽ có tên là name và chúng là thành phần bộ phận của đối tượng có 
tên đặt ở ngay dưới đỉnh stack. 
Ví dụ: xét đoạn mã giả sau 
glInitNames(); 
glPushName(1); 
/* vẽ đối tượng thứ nhất */ 
... 
glPushName(2); 
/* vẽ đối tượng thứ 2 */ 
... 
glPushName(4); 
/* vẽ đối tượng thứ 3 */ 
... 
stack sẽ có nội dung sau 
thì nghĩa là đối tượng (4) là thành phần của đối tượng (2), và đối tượng (2) là thành phần của đối 
tượng (1). 
2.3. Truy vấn đối tượng trong vùng chọn 
Để có thể truy vấn xem đối tượng nào được chọn, OpenGL xử lý như sau 
 trước tiên sẽ đánh dấu mọi đối tượng nào có vùng giao với vùng chọn, 
 sau đó, với mỗi đối tượng có vùng giao, tên của nó và giá trị z nhỏ nhất, z lớn nhất của 
vùng giao sẽ được lưu trong hit records 
 mọi truy vấn về đối tượng được chọn sẽ được thực hiện trên hit records. 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 29 
Như vậy, dựa trên hit records chúng ta biết được các thông tin sau 
1) số recods = số lượng đối tượng cần quan tâm nằm trong vùng chọn 
2) với mỗi record, chúng ta biết được các thông tin sau 
a. tên của đối tượng (bao gồm tên của tất cả các đối tượng mà nó là thành phần) 
b. z_min và z_max của vùng giao giữa đối tượng với vùng chọn (2 con số này nàm 
trong [0,1] và cần phải nhân với 231-1 (0x7fffffff) ). 
Để khởi tạo hit records, chúng ta cần phải gọi hàm 
void glSelectBuffer(GLsizei size, GLuint *buffer) 
trong đó buffer chính là mảng chứa hit records. 
Chú ý: thủ thục này phải được gọi trước khi chuyển sang chế độ GL_SELECT. 
4. Ví dụ 
Trong ví dụ này, tương tự như ví của của chương 3 mục 4, chúng ta sẽ vẽ mô hình trái đất quay 
xung quanh mặt trời. Hơn nữa, chúng ta sẽ cho phép thực hiện các thao tác sau 
 nếu người dùng click vào mặt trời thì mặt trời sẽ được vẽ bằng solid sphere thay vì là 
wire sphere 
 nếu người dùng click vào trái đất thì trái đất sẽ được vẽ bằng solid sphere thay vì là wire 
sphere 
 nếu người dùng click vào vùng không thuộc đối tượng nào thì cả trái đất và mặt trời sẽ 
được vẽ bằng hình mặc định ban đầu là wire sphere 
#include "glut.h" 
#define NON -1 
#define SUN 1 
#define PLANET 2 
static int year = 0, day = 0; 
static int ichosen = NON; // ghi lại xem đối tượng nào đang được chọn, NON 
nghĩa là không có đối tượng nào hết 
void init(void) 
{ 
 glClearColor (0.0, 0.0, 0.0, 0.0); 
 glEnable(GL_DEPTH_TEST); 
 glShadeModel(GL_FLAT); 
} 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 30 
// hàm vẽ tổng quát cho cả chế độ render và chế độ selection 
void draw(GLint mode) 
{ 
 glMatrixMode(GL_MODELVIEW); 
 glPushMatrix(); 
 glColor3f (1.0, 0, 0); 
 if (mode == GL_SELECT) // nếu đang là chế độ selection thì đặt tên cho 
mặt trời 
 glLoadName(SUN); 
 if (ichosen == SUN) // nếu đang chọn SUN thì sẽ vẽ mặt trời khác đi 
 glutSolidSphere(1.0, 50, 50); 
 else 
 glutWireSphere(1.0, 20, 16); // ngược lại thì vẽ như bình thường 
/* di chuyển đến tọa độ mới để vẽ trái đất */ 
 glRotatef ((GLfloat) year, 0.0, 1.0, 0.0); 
 glTranslatef (2.0, 0.0, 0.0); 
 glRotatef ((GLfloat) day, 0.0, 1.0, 0.0); 
 glColor3f (0, 0, 1.0); 
 if (mode == GL_SELECT) // nếu đang là chế độ selection thì đặt tên cho 
mặt trời 
 glLoadName(PLANET); 
 if (ichosen == PLANET) // nếu trái đất đang được chọn thì sẽ vẽ khác đi 
 glutSolidSphere(0.2, 30, 30); 
 else 
 glutWireSphere(0.2, 10, 8); 
 glPopMatrix(); 
} 
void display() 
{ 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 draw(GL_RENDER); 
 glutSwapBuffers(); 
} 
// hàm xử lý hit records 
void processHits (GLint hits, GLuint buffer[]) 
{ 
 unsigned int i, j; 
 GLuint *ptr; 
 float min_z_min; 
 ptr = (GLuint *) buffer; 
 ichosen = NON; 
 /* lặp với mỗi hit, trong trường hợp có nhiều hit thì sẽ chọn đối 
tượng ở gần mắt nhất */ 
 for (i = 0; i < hits; i++) { 
 GLuint names = *ptr; ptr++; 
 float z_min = (float) *ptr/0x7fffffff; ptr++; // giá trị z_min 
của vùng giao đối tượng với vùng chọn 
 float z_max = (float) *ptr/0x7fffffff; ptr++; // giá trị z_max 
 GLuint name = *ptr; 
 ptr++; 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 31 
 if ( i == 0 || min_z_min > z_min ) // chọn đối tượng ở gần mắt 
hơn 
 { 
 min_z_min = z_min; 
 ichosen = name; 
 } 
 } 
 ptr = (GLuint*) buffer; 
} 
#define BUFSIZE 512 
// hàm xử lý thông điệp về mouse 
void pick(int button, int state, int x, int y) 
{ 
 GLuint selectBuf[BUFSIZE]; 
 GLint hits; 
 GLint viewport[4]; 
/* chỉ xử lý khi người dùng click chuột trái */ 
 if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) 
 return; 
 glGetIntegerv (GL_VIEWPORT, viewport); 
 glSelectBuffer (BUFSIZE, selectBuf); // khởi tạo hit records 
 (void) glRenderMode (GL_SELECT); // chọn chế độ selection 
 glInitNames(); // khởi tạo stack tên 
 glPushName(0); // đặt tên cho đối tượng rỗng là 0 
/* thiết lập vùng chọn */ 
 glMatrixMode (GL_PROJECTION); 
 glPushMatrix (); 
 glLoadIdentity (); 
 gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3]- y), 5.0, 5.0, 
viewport); // vùng quan tâm vùng quanh mouse 5x5 pixel 
 gluPerspective(60.0, viewport[2]/viewport[3], 1.0, 20.0); 
 draw(GL_SELECT); // vẽ trong chế độ selection 
 glMatrixMode (GL_PROJECTION); 
 glPopMatrix (); 
 glFlush (); 
 hits = glRenderMode (GL_RENDER); // hits là số hit trong vùng chọn 
 processHits (hits, selectBuf); // xử lý hit records 
 glutPostRedisplay(); // bắt vẽ lại 
} 
void reshape (int w, int h) 
{ 
 glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
 glMatrixMode (GL_PROJECTION); 
 glLoadIdentity (); 
 gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); 
 glMatrixMode(GL_MODELVIEW); 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 32 
 glLoadIdentity(); 
 gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 
} 
void keyboard (unsigned char key, int x, int y) 
{ 
 switch (key) { 
 case 'd': 
 day = (day + 10) % 360; 
 glutPostRedisplay(); 
 break; 
 case 'D': 
 day = (day - 10) % 360; 
 glutPostRedisplay(); 
 break; 
 case 'y': 
 year = (year + 5) % 360; 
 glutPostRedisplay(); 
 break; 
 case 'Y': 
 year = (year - 5) % 360; 
 glutPostRedisplay(); 
 break; 
 default: 
 break; 
 } 
} 
int main(int argc, char** argv) 
{ 
 glutInit(&argc, argv); 
 glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); 
 glutInitWindowSize (500, 500); 
 glutInitWindowPosition (100, 100); 
 glutCreateWindow (argv[0]); 
 init (); 
 glutDisplayFunc(display); 
 glutReshapeFunc(reshape); 
 glutKeyboardFunc(keyboard); 
 glutMouseFunc(pick); // thiết lập hàm pick xử lý thông điệp mouse 
 glutMainLoop(); 
 return 0; 
} 
Kết quả khi click vào mặt trời 
Hướng dẫn lập trình OpenGL căn bản 
Đặng Nguyễn Đức Tiến – Vũ Quốc Hoàng - Lê Phong Page 33 

File đính kèm:

  • pdfhuong_dan_lap_trinh_opengl_can_ban.pdf