Chương 3. Màu sắc và thuật toán tô màu môn Đồ họa máy tính | Trường đại học kinh doanh và công nghệ Hà Nội
Giải thuật này thường được dùng để tô màu các đa giác, đường tròn,ellipse, và một số đường cong đơn giản khác. Giải thuật tô theo dòng quét (scan-line fill): tìm giao điểm của dòng quét ngang với các cạnh của đa giác. Từ các giao điểm, xác định các đoạn con nằm bên trong đa giác, rồi tô màu các đoạn con này. Tài liệu giúp bạn tham khảo, ôn tập và đạt kết quả cao. Mời đọc đón xem!
Preview text:
lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Chương 3. Màu sắc và thuật toán tô màu (tiếp theo) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
5. Tô màu theo dòng quét
Giải thuật này thường ược dùng ể tô màu các a giác, ường tròn, ellipse, và
một số ường cong ơn giản khác.
Giải thuật tô theo dòng quét (scan-line fill): tìm giao iểm của dòng quét
ngang với các cạnh của a giác. Từ các giao iểm, xác ịnh các oạn con nằm bên
trong a giác, rồi tô màu các oạn con này.
Đối với mỗi dòng quét, cần tìm các giao iểm của dòng quét với a giác.
Các giao iểm cần ược sắp xếp theo thứ tự tăng dần theo hoành ộ: x1, x2,..., x2n
(n>0). Tô các oạn x1..x2; x3..x4;...; x2n-1..x2n.
Khi dòng quét i qua một ỉnh của a giác: -
Nếu 2 cạnh từ ỉnh này nằm cùng phía với dòng quét thì tính là 2 giao iểm. -
Nếu 2 cạnh từ ỉnh này nằm khác phía với dòng quét thì tính là 1 giao iểm.
Nếu cạnh a giác trùng với dòng quét thì không cần tô cạnh này.
Trên cùng một cạnh, giao iểm của dòng quét kế ược tính dựa theo giao
iểm của dòng quét trước: - m = dy/dx = (yb-ya)/(xb-xa) -
Giao iểm ở ầu oạn: A(xa, ya) -
Giao iểm tiếp theo: (xa + 1/m, ya + 1) -
Giao iểm tiếp theo: (xa + 1/m + 1/m, ya + 1 + 1) = (xa + 2/m, ya + 2) - v.v…. lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh B(xb,yb) ya +1 xa +1/m ya A(xa,ya) Giải thuật:
1/ Đối với mỗi cạnh không nằm ngang của biên a giác, xác ịnh ỉnh trên và
dưới, (xl, yl) và (xu, yu), sao cho yu > yl và tạo một mẫu tin cho mỗi cạnh -
yu, tọa ộ y tại ỉnh trên -
x = xl, giao iểm x hiện tại -
w = 1/m = (xu − xl)/(yu − yl), với m là hệ số góc của cạnh
2/ Đặt bảng AET (active edge table /bảng cạnh ang hoạt ộng) bằng rỗng.
3/ Áp dụng thuật toán sắp xếp nhóm (bucket) ể sắp xếp các cạnh với yl làm
khóa chính, xl làm khóa phụ và w làm khóa phụ kế. Mỗi nhóm chứa một danh
sách. Tập hợp các nhóm ược gọi là bảng ET (edge table /bảng cạnh):
4/ Đặt y bằng chỉ số nhỏ nhất trong ET có nhóm không rỗng.
5/ Lặp lại cho ến khi hết ET và AET:
(a) Dời bất kỳ cạnh nào từ nhóm y trong ET sang AET.
(b) Loại bỏ bất kỳ cạnh nào khỏi AET mà có yu bằng y. lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh (c) Sắp xếp AET theo x.
(d) Vẽ (tô) các oạn giữa các cặp giao iểm lẻ và chẵn liền kề trong AET:
làm tròn lên tọa ộ x của các giao iểm bên trái, làm tròn xuống tọa ộ x của các giao iểm bên phải. (e) Tăng y thêm một.
(f) Cập nhật x = x + w cho mọi cạnh không thẳng ứng trong AET. Bảng AET
Ký hiệu 1/m [1,5] là W15 = 1/m , với m là hệ số góc của oạn thẳng từ ỉnh
thứ 1 ến ỉnh thứ 5.
6. Tô màu với OpenGL
a. Chỉ ịnh hệ màu
Hàm glutInitDisplayMode ược dùng ể chỉ ịnh chế ộ màu GLUT_RGBA hoặc GLUT_INDEX.
GLUT_RGBA là hệ màu mặc ịnh trong OpenGL.
Hàm này ược viết trong hàm main.
VD: glutInitDisplayMode(GLUT_RGB);
GLUT_RGB là bí danh của GLUT_RGBA. lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh b. Tô màu ơn
Sử dụng glPolygonMode(face, mode) và glColor* ể thiết lập mặt tô và
màu nền (hoặc màu ường vẽ) của hình vẽ.
c. Tô màu phối hợp
Mỗi ỉnh của hình vẽ có màu khác nhau. glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0f); // Red glVertex2f(0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f); // Green glVertex2f(0.3f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f); // Blue glVertex2f(0.3f, 0.3f);
glColor3f(1.0f, 1.0f, 0.0f); // Yellow
glVertex2f(0.0f, 0.3f); glEnd();
d. Tô màu và vẽ ường
Vẽ hình thứ 1 với màu nền, sau ó vẽ hình thứ 2 trùng với hình thứ 1 mà chỉ vẽ ường. glBegin(GL_TRIANGLES); glColor3f(0.0, 0.0, 1.0); lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh glVertex2i(50, 50); glColor3f(1.0, 0.0, 0.0); glVertex2i(150, 50); glColor3f(0.0, 1.0, 0.0); glVertex2i(75, 150); glEnd(); glColor3f(1.0, 0.0, 0.0);
glPolygonMode(GL_FRONT, GL_LINE); glBegin(GL_TRIANGLES); glVertex2i(50, 50); glVertex2i(150, 50); glVertex2i(75, 150); glEnd(); glFlush();
e. Tô màu bằng mẫu cho a giác lồi
1/ Định nghĩa mẫu tô bằng ma trận 32x32 bit (= 1024 bit).
VD: Mẫu tô là hình con ruồi. Mỗi ô là 1 bit dữ liệu. Nếu ô màu en thì bit
có giá trị 1. Ngược lại bit có giá trị 0. lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Đi từ hàng dưới lên, i trừ phải sang trái, ta có các bit dữ liệu sau:
Hàng 0: 00000000, 00000000, 00000000, 00000000,
Hàng 1: 00000000, 00000000, 00000000, 00000000,
Hàng 2: 00000011, 10000000, 00000001, 11000000, ….
Cứ mỗi 4 bit số nhị phân, ta chuyển sang 1 chữ số hệ 16 (thập lục phân):
4 bit số nhị phân Số hệ 16 4 bit số nhị phân Số hệ 16 0000 0 1000 8 0001 1 1001 9 0010 2 1010 A 0011 3 1011 B 0100 4 1100 C 0101 5 1101 D 0110 6 1110 E 0111 7 1111 F Vậy lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh Hàng 0: 00, 00, 00, 00, Hàng 1: 00, 00, 00, 00, Hàng 2: 03, 80, 01, C0 ….
2 số hệ 16 gộp lại thành 1 byte. Để chỉ báo số hệ 16 cần thêm tiền số 0x.
2/ Ta lưu các số hệ 16 của ma trận mẫu tô vào mảng 1 chiều như sau: GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08 };
3/ Các hàm thiết lập việc tô theo mẫu:
void glEnable(GL_POLYGON_STIPPLE): cho phép tô theo mẫu void
glDisable(GL_POLYGON_STIPPLE): không cho phép tô theo mẫu lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
void glPolygonStipple(const GLubyte *mask): chỉ ịnh mẫu tô, mask là
tham số nhận ma trận mẫu tô.
Xem thêm glPixelStore* và GL_UNPACK*
Ví dụ: Hình chữ nhựt thứ 1 có nền trắng theo mặc ịnh. Hình chữ nhựt thứ
2 có mẫu tô là các ường chấm chấm, mẫu tô này ược thiết lập lại là màu blue bằng
hàm glColor3f. Hình chữ nhựt thứ 3 có mẫu tô là hình con ruồi, mẫu tô này ược
thiết lập là màu green bằng hàm glColor3f. Hình chữ nhựt thứ 4 có nền ơn màu
green như màu hình thứ 3. #include void display(void) { GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0, lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08 }; lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh GLubyte pattern[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//Màu nền theo mặc ịnh
glRectf(25.0f, 25.0f, 125.0f, 300.0f); //hình chữ nhựt thứ 1 //Màu nền blue glColor3f(0.0f, 0.0f, 1.0f); //cho phép mẫu tô glEnable(GL_POLYGON_STIPPLE); //tô theo mẫu pattern glPolygonStipple(pattern);
glRectf(125.0f, 25.0f, 225.0f, 300.0f); //hình chữ nhựt thứ 2 //Màu nền green glColor3f(0.0f, 1.0f, 0.0f); //tô theo mẫu fly glPolygonStipple(fly); Trang 11 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
glRectf(225.0f, 25.0f, 325.0f, 300.0f); //hình chữ nhựt thứ 3 //không cho phép mẫu tô
glDisable(GL_POLYGON_STIPPLE);
//Màu nền theo mặc ịnh
glRectf(325.0f, 25.0f, 425.0f, 300.0f); //hình chữ nhựt thứ 4 glFlush(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(500, 500); glutCreateWindow("My App!"); glutDisplayFunc(display); gluOrtho2D(0.0, 500.0, 0.0, 500.0); glutMainLoop(); return 0; }
Lưu ý: Nếu không tô mẫu nền mới và không cấm tô mẫu nền, thì hình chữ
nhựt thứ 4 sẽ có mẫu nền như hình thứ 3.
f. Tô màu bằng mẫu cho a giác không lồi
OpenGL chỉ tô theo mẫu cho a giác lồi.
Giải pháp: Ta chia nhỏ a giác không lồi thành các a giác lồi, thường là thành
các tam giác. Ta vẽ các a giác lồi này và tô nền chúng. Tuy nhiên, nó sẽ vẽ luôn
các cạnh không mong muốn bên trong a giác.
VD: Đa giác không lồi ban ầu ược chia thành 3 tam giác ể vẽ. Nó dư thừa
các cạnh so với a giác ban ầu. Trang 12
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Khắc phục: Khi vẽ một a giác, ta có thể cho phép cạnh nào ược vẽ hoặc
không ược vẽ. glEdgeFlag(GL_TRUE): cho phép cạnh ược vẽ.
glEdgeFlag(GL_FALSE): không cho phép cạnh ược vẽ. VD:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.0f, 0.0f, 1.0f); glBegin(GL_POLYGON);
glEdgeFlag(GL_TRUE); //cạnh i từ ỉnh sau ây sẽ ược vẽ glVertex2i(200,250);
glEdgeFlag(GL_TRUE); //cạnh i từ ỉnh sau ây sẽ ược vẽ glVertex2i(180,350);
glEdgeFlag(GL_FALSE); //cạnh i từ ỉnh sau ây không ược vẽ glVertex2i(130,300); glEnd();
VD: Vẽ lại hình a giác trên bằng các tam giác và có tô nền theo mẫu. Sử
dụng glEdgeFlag ể không vẽ các cạnh không mong muốn. #include void display(void) { GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Trang 13 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08 }; glEnable(GL_POLYGON_STIPPLE); glPolygonStipple(fly);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.0f, 0.0f, 1.0f); //vẽ tam giác thứ 1 glBegin(GL_POLYGON); glEdgeFlag(GL_TRUE); glVertex2i(200,250); glEdgeFlag(GL_TRUE); glVertex2i(180,350); glEdgeFlag(GL_FALSE); glVertex2i(130,300); glEnd(); //vẽ tam giác thứ 2 Trang 14
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh glBegin(GL_POLYGON); glEdgeFlag(GL_TRUE); glVertex2i(130, 300); glEdgeFlag(GL_TRUE); glVertex2i(20, 350); glEdgeFlag(GL_FALSE); glVertex2i(20, 250); glEnd(); //vẽ tam giác thứ 3 glBegin(GL_POLYGON); glEdgeFlag(GL_TRUE); glVertex2i(20, 250); glEdgeFlag(GL_FALSE); glVertex2i(200, 250); glEdgeFlag(GL_FALSE); glVertex2i(130, 300); glEnd(); glFlush(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(500, 500); glutCreateWindow("My App!"); glutDisplayFunc(display); gluOrtho2D(0.0, 500.0, 0.0, 500.0); glutMainLoop(); return 0; }
Lưu ý: Khi tô nền theo mẫu, bỏ thiết lập chế ộ vẽ ường. Trang 15 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh Trang 16
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh BÀI TẬP Thực hành
1. Thiết kế mẫu, viết chương trình toán tô theo mẫu bằng glPolygonStipple cho
hình vương miện sau (phải có ường vẽ) Trang 17 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)