OpenGL là một công cụ lập trình 3D mạnh mẽ được sử dụng để vẽ các cảnh ba chiều phức tạp từ các nguyên bản đơn giản. Bài viết này sẽ dạy bạn cách vẽ một khối lập phương đơn giản mà bạn có thể quay để xem trong không gian ba chiều!
Đối với dự án này, bạn sẽ cần một trình soạn thảo mã và một số kiến thức về lập trình C.
Các bước
Phần 1/3: Thiết lập ban đầu
Bước 1. Cài đặt OpenGL Để bắt đầu, hãy làm theo các bước sau để cài đặt OpenGL trên hệ thống của bạn
Nếu bạn đã cài đặt OpenGL, cũng như trình biên dịch C tương thích, bạn có thể bỏ qua bước này và chuyển sang bước tiếp theo.
Bước 2. Tạo tài liệu
Tạo một tệp mới trong trình soạn thảo mã yêu thích của bạn và lưu nó dưới dạng mycube.c
Bước 3. Thêm #includes
Đây là những điều cơ bản mà bạn sẽ cần cho chương trình của mình. Điều quan trọng là phải nhận ra rằng có những bao gồm thực sự khác nhau được yêu cầu cho các hệ điều hành khác nhau. Đảm bảo bao gồm tất cả những điều này để đảm bảo chương trình của bạn đa năng và có thể chạy cho bất kỳ người dùng nào.
// Bao gồm #include #include #include #define GL_GLEXT_PROTOTYPES #ifdef _APPLE_ #include #else #include #endif
Bước 4. Thêm nguyên mẫu hàm và biến toàn cục
Bước tiếp theo của bạn là khai báo một số nguyên mẫu hàm.
// Nguyên mẫu hàm void display (); void specialKeys (); // Biến toàn cục double xoay_y = 0; xoay kép_x = 0;
Bước 5. Thiết lập hàm main ()
int main (int argc, char * argv ) {// Khởi tạo GLUT và xử lý tham số người dùng glutInit (& argc, argv); // Yêu cầu cửa sổ màu thực được đệm kép với Z-buffer glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
Bước 6. Tạo cửa sổ
Bước tiếp theo là tạo cửa sổ trong đó bạn sẽ vẽ khối lập phương. Trong hướng dẫn này, cửa sổ được gọi là "Awesome Cube".
// Tạo cửa sổ glutCreateWindow ("Awesome Cube");
Bước 7. Kích hoạt kiểm tra độ sâu
OpenGL là một ngôn ngữ nghiêm ngặt trong đó nó không giả định rằng bất kỳ tính năng đặc biệt nào được kích hoạt. Để chương trình của bạn hiển thị đúng 3 chiều bằng cách sử dụng Z-buffer mà bạn đã xem trước đó, bạn cần cho phép kiểm tra độ sâu. Khi bạn tiếp tục khám phá OpenGL, bạn sẽ khám phá ra nhiều tính năng mà bạn sẽ cần bật bao gồm ánh sáng, kết cấu, mặt khối và nhiều tính năng khác.
// Bật kiểm tra độ sâu Z-buffer glEnable (GL_DEPTH_TEST);
Bước 8. Thêm các chức năng gọi lại
Đây là các hàm gọi lại mà bạn đã viết các nguyên mẫu trước đó. Mỗi lần qua vòng lặp chính, các hàm này sẽ được gọi. Hàm hiển thị vẽ lại cảnh dựa trên bất kỳ thay đổi nào đối với các biến đã được thực hiện kể từ lần gọi trước. Chức năng SpecialKeys cho phép chúng ta tương tác với chương trình.
// Gọi lại các hàm glutDisplayFunc (display); glutSpecialFunc (specialKeys);
Bước 9. Khởi động MainLoop
Thao tác này sẽ gọi lại chức năng chính cho đến khi bạn đóng chương trình để cho phép hoạt ảnh và tương tác với người dùng.
// Chuyển quyền điều khiển tới GLUT cho các sự kiện glutMainLoop (); // Quay lại hệ điều hành return 0; }
Phần 2/3: Hàm display ()
Bước 1. Hiểu mục đích của chức năng này
Tất cả công việc vẽ hình khối của bạn sẽ được thực hiện trong chức năng này. Ý tưởng chung đằng sau khối lập phương của bạn là vẽ tất cả sáu cạnh riêng lẻ và đặt chúng vào vị trí thích hợp.
Về mặt khái niệm, mỗi cạnh sẽ được vẽ bằng cách xác định bốn góc và cho phép OpenGL kết nối các đường và tô nó bằng màu do bạn xác định. Dưới đây là các bước để thực hiện việc này
Bước 2. Thêm glClear ()
Bước đầu tiên bạn cần thực hiện trong chức năng này là xóa màu và đệm Z. Nếu không có các bước này, các bản vẽ cũ có thể vẫn hiển thị dưới các bản vẽ mới và các đối tượng được vẽ sẽ không ở đúng vị trí trên màn hình.
void display () {// Xóa màn hình và Z-buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Bước 3. Thêm glBegin () và glEnd ()
OpenGL định nghĩa các đối tượng là sự kết hợp của các đa giác khác nhau. Sử dụng glBegin () lệnh, bạn đặt bút chì xuống một cách hiệu quả sẽ vẽ một hình dạng. Để nhấc bút chì lên và bắt đầu một hình dạng mới, bạn phải sử dụng glEnd () chỉ huy. Trong hướng dẫn này, bạn sẽ sử dụng GL_POLYGON để vẽ từng mặt của khối lập phương nhưng có thể sử dụng các tùy chọn tham số khác như GL_LINE, GL_QUAD hoặc GL_TRIANGLE để tạo các hình dạng khác.
- Ở đây bạn sẽ bắt đầu với mặt trước của khối lập phương của bạn. Sau đó, bạn sẽ thêm màu cho tất cả 6 mặt.
// Mặt nhiều màu - FRONT glBegin (GL_POLYGON); // Các đỉnh sẽ được thêm vào trong bước tiếp theo glEnd ();
Bước 4. Thêm glVertex3f ()
Khi bạn đã tuyên bố rằng bạn muốn bắt đầu đa giác của mình, bạn cần xác định các đỉnh của đối tượng. glVertex có nhiều dạng tùy thuộc vào những gì bạn muốn làm với đối tượng của mình.
- Đầu tiên là bạn đang làm việc trong bao nhiêu kích thước. 3 thứ trên trong glVertex3f cho biết bạn đang vẽ 3 chiều. Nó cũng có thể làm việc trong 2 hoặc 4 chiều. F ở trên trong glVertex3f cho biết bạn đang làm việc với số dấu phẩy động. Bạn cũng có thể sử dụng quần đùi, số nguyên hoặc đồ đôi.
- Lưu ý rằng những điểm này được xác định trong một ngược chiều kim đồng hồ cách thức. Điều này không quá quan trọng vào lúc này nhưng khi bạn bắt đầu làm việc với ánh sáng, kết cấu và mặt phẳng, điều này sẽ trở nên cực kỳ quan trọng, vì vậy hãy tập thói quen xác định điểm của bạn ngược chiều kim đồng hồ ngay từ bây giờ.
- Thêm thêm các đỉnh giữa các dòng glBegin () và glEnd ().
// Mặt nhiều màu - FRONT glBegin (GL_POLYGON); glVertex3f (-0,5, -0,5, -0,5); // P1 glVertex3f (-0,5, 0,5, -0,5); // P2 glVertex3f (0.5, 0.5, -0.5); // P3 glVertex3f (0.5, -0.5, -0.5); // P4 glEnd ();
Bước 5. Thêm glColor3f ()
glColor hoạt động theo cách tương tự như glVertex. Bạn có thể xác định các điểm dưới dạng quần ngắn, số nguyên, số đôi hoặc số nổi. Mỗi màu có giá trị từ 0 đến 1. Tất cả các số 0 làm cho điểm có màu đen và tất cả các màu 1 sẽ làm cho điểm có màu trắng. 3 trong glColor3f () đề cập đến hệ màu RGB không có kênh alpha. Alpha của một màu xác định độ trong suốt của nó. Để thay đổi mức alpha, hãy sử dụng glColor4f () với tham số cuối cùng là giá trị từ 0 đến 1 cho từ mờ đến trong suốt.
- Khi bạn gọi glColor3f (), mọi đỉnh được vẽ từ điểm đó trở đi sẽ có màu đó. Do đó, nếu bạn muốn tất cả bốn đỉnh có màu đỏ, chỉ cần thiết lập màu một lần trước các lệnh glVertex3f () và tất cả các đỉnh sẽ có màu đỏ.
- Mặt trước được xác định dưới đây cho thấy cách xác định màu mới cho mỗi đỉnh. Khi bạn làm điều này, bạn có thể thấy một thuộc tính thú vị của màu OpenGL. Vì mỗi đỉnh của đa giác có màu riêng, OpenGL sẽ tự động pha trộn các màu! Bước tiếp theo sẽ chỉ ra cách gán bốn đỉnh có cùng màu.
// Mặt nhiều màu - FRONT glBegin (GL_POLYGON); glColor3f (1,0, 0,0, 0,0); glVertex3f (0,5, -0,5, -0,5); // P1 là màu đỏ glColor3f (0.0, 1.0, 0.0); glVertex3f (0,5, 0,5, -0,5); // P2 có màu xanh lục glColor3f (0.0, 0.0, 1.0); glVertex3f (-0,5, 0,5, -0,5); // P3 có màu xanh lam glColor3f (1.0, 0.0, 1.0); glVertex3f (-0,5, -0,5, -0,5); // P4 là màu tím glEnd ();
Bước 6. Xử lý các mặt còn lại
Tìm ra vị trí của mỗi đỉnh đối với năm cạnh còn lại của hình lập phương nhưng để đơn giản, chúng đã được tính toán cho bạn và được đưa vào hàm hiển thị cuối cùng () phía dưới.
// Mặt trắng - BACK glBegin (GL_POLYGON); glColor3f (1.0, 1.0, 1.0); glVertex3f (0,5, -0,5, 0,5); glVertex3f (0,5, 0,5, 0,5); glVertex3f (-0,5, 0,5, 0,5); glVertex3f (-0,5, -0,5, 0,5); glEnd (); // Mặt màu tím - RIGHT glBegin (GL_POLYGON); glColor3f (1.0, 0.0, 1.0); glVertex3f (0,5, -0,5, -0,5); glVertex3f (0,5, 0,5, -0,5); glVertex3f (0,5, 0,5, 0,5); glVertex3f (0,5, -0,5, 0,5); glEnd (); // Mặt xanh - LEFT glBegin (GL_POLYGON); glColor3f (0,0, 1,0, 0,0); glVertex3f (-0,5, -0,5, 0,5); glVertex3f (-0,5, 0,5, 0,5); glVertex3f (-0,5, 0,5, -0,5); glVertex3f (-0,5, -0,5, -0,5); glEnd (); // Mặt xanh - TOP glBegin (GL_POLYGON); glColor3f (0,0, 0,0, 1,0); glVertex3f (0,5, 0,5, 0,5); glVertex3f (0,5, 0,5, -0,5); glVertex3f (-0,5, 0,5, -0,5); glVertex3f (-0,5, 0,5, 0,5); glEnd (); // Mặt đỏ - BOTTOM glBegin (GL_POLYGON); glColor3f (1,0, 0,0, 0,0); glVertex3f (0,5, -0,5, -0,5); glVertex3f (0,5, -0,5, 0,5); glVertex3f (-0,5, -0,5, 0,5); glVertex3f (-0,5, -0,5, -0,5); glEnd (); glFlush (); glutSwapBuffers (); }
Chúng tôi cũng muốn thêm vào hai dòng mã cuối cùng cho chức năng này. đó là glFlush ();
và glutSwapBuffers ();
cung cấp cho chúng tôi hiệu ứng đệm kép mà bạn đã biết trước đó.
Phần 3/3: Tương tác của người dùng
Bước 1. Thêm specialKeys ()
Bạn gần như đã hoàn thành nhưng hiện tại, bạn có thể vẽ một khối lập phương nhưng không có cách nào để xoay nó. Để làm điều này, bạn sẽ tạo một SpecialKeys () chức năng cho phép chúng ta nhấn các phím mũi tên và xoay khối lập phương!
- Hàm này là lý do tại sao bạn khai báo các biến toàn cục là xoay_x và xoay_y. Khi bạn nhấn các phím mũi tên phải và trái, xoay_y sẽ tăng hoặc giảm 5 độ. Tương tự, khi bạn nhấn phím mũi tên lên và xuống, thì xoay_x sẽ thay đổi theo.
void specialKeys (int key, int x, int y) {// Mũi tên phải - tăng vòng quay thêm 5 độ if (key == GLUT_KEY_RIGHT) xoay_y + = 5; // Mũi tên trái - giảm xoay 5 độ else if (key == GLUT_KEY_LEFT) xoay_y - = 5; else if (key == GLUT_KEY_UP) xoay_x + = 5; else if (key == GLUT_KEY_DOWN) xoay_x - = 5; // Yêu cầu cập nhật hiển thị glutPostRedisplay (); }
Bước 2. Thêm glRotate ()
Câu lệnh cuối cùng của bạn là thêm câu lệnh sẽ xoay đối tượng của bạn. Quay lại hàm display () và trước cạnh TRƯỚC, thêm các dòng sau:
// Đặt lại các phép biến đổi glLoadIdentity (); // Xoay khi người dùng thay đổi rot_x và xoay_y glRotatef (xoay_x, 1.0, 0.0, 0.0); glRotatef (xoay_yêu, 0.0, 1.0, 0.0); // Mặt nhiều màu - TRƯỚC….
Bước 3. Thêm các lệnh sau để chia tỷ lệ hình lập phương theo 2 dọc theo trục x, 2 theo trục y, xoay hình lập phương 180 độ theo trục y và dịch hình lập phương 0,1 dọc theo trục x
Đảm bảo sắp xếp các lệnh này cũng như các lệnh glRotate () trước đó theo đúng thứ tự như đã mô tả ở trên. (Nếu bạn không chắc chắn, điều này được thực hiện trong đoạn mã cuối cùng ở cuối hướng dẫn.)
// Các phép biến đổi khác glTranslatef (0,1, 0,0, 0,0); glRotatef (180, 0.0, 1.0, 0.0); glScalef (2.0, 2.0, 0.0);
Bước 4. Biên dịch và chạy mã của bạn
Giả sử bạn đang sử dụng gcc làm trình biên dịch của mình, hãy chạy các lệnh này từ thiết bị đầu cuối để biên dịch và kiểm tra chương trình của bạn.
Trên Linux: gcc cube.c -o cube -lglut -lGL./ mycube Trên Mac: gcc -o foo foo.c -framework GLUT -framework OpenGL./ mycube Trên Windows: gcc -Wall -ofoo foo.c -lglut32cu - lglu32 -lopengl32./ mycube
Bước 5. Kiểm tra mã hoàn chỉnh của bạn
Nó sẽ như thế này:
// // File: mycube.c // Author: Matt Daisley // Created: 4/25/2012 // Project: Source code for Make a Cube in OpenGL // Description: Tạo một cửa sổ OpenGL và vẽ một hình khối 3D / / Người dùng có thể xoay bằng các phím mũi tên // // Điều khiển: Mũi tên trái - Xoay trái // Mũi tên phải - Xoay phải // Mũi tên lên - Xoay lên // Mũi tên xuống - Xoay xuống // ------ -------------------------------------------------- -- // Bao gồm // ------------------------------------------- --------------- #include #include #include #define GL_GLEXT_PROTOTYPES #ifdef _APPLE_ #include #else #include #endif // ------------- --------------------------------------------- // Nguyên mẫu hàm / / ------------------------------------------------- --------- void display (); void specialKeys (); // ------------------------------------------------ ---------- // Biến toàn cục // ---------------------------------- ------------------------ double xoay_y = 0; xoay kép_x = 0; // ------------------------------------------------ ---------- // Hàm gọi lại display () // ------------------------------- --------------------------- void display () {// Xóa màn hình và Z-buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Đặt lại các phép biến đổi glLoadIdentity (); // Các biến đổi khác // glTranslatef (0.1, 0.0, 0.0); // Không bao gồm // glRotatef (180, 0.0, 1.0, 0.0); // Không bao gồm // Xoay khi người dùng thay đổi xoay_x và xoay_y glRotatef (xoay_x, 1.0, 0.0, 0.0); glRotatef (xoay_y, 0,0, 1,0, 0,0); // Các biến đổi khác // glScalef (2.0, 2.0, 0.0); // Không bao gồm // Mặt nhiều màu - FRONT glBegin (GL_POLYGON); glColor3f (1,0, 0,0, 0,0); glVertex3f (0,5, -0,5, -0,5); // P1 là màu đỏ glColor3f (0.0, 1.0, 0.0); glVertex3f (0,5, 0,5, -0,5); // P2 có màu xanh lục glColor3f (0.0, 0.0, 1.0); glVertex3f (-0,5, 0,5, -0,5); // P3 có màu xanh lam glColor3f (1.0, 0.0, 1.0); glVertex3f (-0,5, -0,5, -0,5); // P4 là màu tím glEnd (); // Mặt trắng - BACK glBegin (GL_POLYGON); glColor3f (1.0, 1.0, 1.0); glVertex3f (0,5, -0,5, 0,5); glVertex3f (0,5, 0,5, 0,5); glVertex3f (-0,5, 0,5, 0,5); glVertex3f (-0,5, -0,5, 0,5); glEnd (); // Mặt màu tím - RIGHT glBegin (GL_POLYGON); glColor3f (1.0, 0.0, 1.0); glVertex3f (0,5, -0,5, -0,5); glVertex3f (0,5, 0,5, -0,5); glVertex3f (0,5, 0,5, 0,5); glVertex3f (0,5, -0,5, 0,5); glEnd (); // Mặt xanh - LEFT glBegin (GL_POLYGON); glColor3f (0,0, 1,0, 0,0); glVertex3f (-0,5, -0,5, 0,5); glVertex3f (-0,5, 0,5, 0,5); glVertex3f (-0,5, 0,5, -0,5); glVertex3f (-0,5, -0,5, -0,5); glEnd (); // Mặt xanh - TOP glBegin (GL_POLYGON); glColor3f (0,0, 0,0, 1,0); glVertex3f (0,5, 0,5, 0,5); glVertex3f (0,5, 0,5, -0,5); glVertex3f (-0,5, 0,5, -0,5); glVertex3f (-0,5, 0,5, 0,5); glEnd (); // Mặt đỏ - BOTTOM glBegin (GL_POLYGON); glColor3f (1,0, 0,0, 0,0); glVertex3f (0,5, -0,5, -0,5); glVertex3f (0,5, -0,5, 0,5); glVertex3f (-0,5, -0,5, 0,5); glVertex3f (-0,5, -0,5, -0,5); glEnd (); glFlush (); glutSwapBuffers (); } // ----------------------------------------------- ----------- // Hàm gọi lại specialKeys () // ------------------------------ ---------------------------- void specialKeys (int key, int x, int y) {// Mũi tên phải - tăng vòng quay lên 5 độ if (phím == GLUT_KEY_RIGHT) xoay_y + = 5; // Mũi tên trái - giảm xoay 5 độ else if (key == GLUT_KEY_LEFT) xoay_y - = 5; else if (key == GLUT_KEY_UP) xoay_x + = 5; else if (key == GLUT_KEY_DOWN) xoay_x - = 5; // Yêu cầu cập nhật hiển thị glutPostRedisplay (); } // ----------------------------------------------- ----------- // chức năng chính // ------------------------------- --------------------------- int main (int argc, char * argv ) {// Khởi tạo GLUT và xử lý tham số người dùng glutInit (& argc, argv); // Yêu cầu cửa sổ màu thực được đệm kép với Z-buffer glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Tạo cửa sổ glutCreateWindow ("Awesome Cube"); // Bật kiểm tra độ sâu Z-buffer glEnable (GL_DEPTH_TEST); // Gọi lại các hàm glutDisplayFunc (display); glutSpecialFunc (specialKeys); // Chuyển điều khiển tới GLUT cho các sự kiện glutMainLoop (); // Quay lại hệ điều hành return 0; }