You are on page 1of 56

Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Giáo trình môn Đồ họa máy tính


3
Môn học: Đồ họa máy tính

Giảng viên: TS. Nguyễn Thế Lộc – Khoa CNTT – ĐHSP HN,
email: locnt@hnue.edu.vn
Home page: http://user.hnue.edu.vn/?name=locnt

Thời lượng: 45 tiết (30 tiết lý thuyết + 15 tiết thực hành trên máy)

Tài liệu tham khảo:


[1] Nhập môn đồ họa, Lương Chi Mai, Huỳnh Thị Thanh Bình, 2000
[2] Kỹ thuật đồ họa máy tính, Lê Tấn Hùng, Huỳnh Quyết Thắng, 2004
[3] Cơ sở đồ họa máy tính, Hoàng Kiếm, 1999
[4] Đồ họa vi tính, Huỳnh Văn Đức, Nguyễn Quốc Cường, Hoàng Đức Hải
[5] Computer Graphic, J.D. Foley, A.V. Dam

Đánh giá:
- Câu hỏi trên lớp
- Bài kiểm tra điều kiện
- Bài tập lớn (?)
- Thi: vấn đáp / viết

http://www.ebook.edu.vn 1
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chương I: Giới thiệu về đồ họa máy tính

Thuật ngữ “Đồ họa máy tính – Computer Graphics” được đề xuất bởi một nhà khoa học Mỹ
tên là Wiliam Fetter vào năm 1960 khi ông đang nghiên cứu xây dựng mô hình buồng lái
máy bay cho hãng Boing. Đồ họa máy tính có thể được hiểu như là tất cả những gì liên quan
đến việc tạo ra ảnh (image) bằng máy tính. Chúng bao gồm: tạo, lưu trữ, thao tác trên các
mô hình và các ảnh. W. Fetter đã dựa trên các hình ảnh ba chiều của mô hình người phi
công trong buồng lái để xây dựng nên mô hình tối ưu cho buồng lái máy bay Boing.

1. Tổng quan về một hệ đồ họa


Các thành phần phần cứng:
• Thiết bị hiển thị: màn hình, máy in
• Thiết bị nhập: bàn phím, chuột

Cấu tạo của màn hình dạng điểm (raster – scan display): chùm tia điện tử được quét ngang
qua màn hình mỗi lần 1 dòng và quét tuần tự từ trên xuống dưới. Việc bật tắt các điểm sáng
trên màn hình phụ thuộc vào cường độ của tia điện tử và đây là cơ sở cho việc tạo ra hình
ảnh trên màn hình,

Mỗi điểm sáng trên màn hình được gọi là pixel. Các thông tin về hình ảnh trên màn hình
được lưu trữ trong vùng nhớ đệm gọi là bộ nhớ màn hình (refresh buffer). Để thay đổi hình
ảnh trên màn hình, cần làm thay đổi thông tin trong vùng nhớ đệm. Vùng này có thể nằm
trên Video card hay trích ra từ bộ nhớ chính.

Để tạo ra ảnh Đen - Trắng, chỉ cần lưu thông tin của mỗi pixel bẳng 1 bit( 1/0 = bật/tắt điểm
ảnh). Trong trường hợp ảnh nhiều màu, người ta cần nhiều bit hơn. Nếu ta dùng b bit thì có
thể lưu trữ được 2b giá trị màu khác nhau.

Các công cụ phần mềm:


• Công cụ ứng dụng (application package):được thiết kế cho người sử dụng để tạo ra
ảnh trong những lĩnh vực chuyên nghiệp nào đó mà không cần quan tâm tới các thao
tác bên trong hoạt động ra sao. Ví dụ: AutoCAD, Adobe Photoshop, ...
• Công cụ lập trình: (programming package): cung cấp một thư viện các hàm đồ họa để
dùng trong các ngôn ngữ lập trình cấp cao. Ví dụ: GRAPH.TPU (Pascal), Open GL

2. Các ứng dụng của đồ họa máy tính (computer graphics)


Công cụ hỗ trợ thiết kế (CAD/CAM)
Hỗ trợ thiết kế được xem là một ứng dụng chính của đồ họa máy tính, trong đó đối tượng
được xây dựng trực tiếp là mô hình thiết kế. Hiện nay đồ họa máy tính được ứng dụng trong
việc thiết kế
• các chi tiết cơ khí
• hệ thống điện
• thiết bị điện tử
• thiết kế thân ô tô
• hệ thống cáp quang

http://www.ebook.edu.vn 2
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
• mạng truyền thông
• và rất nhiều thứ khác ...

Các chi tiết sẽ được vẽ trên màn hình nhờ các công cụ đồ họa ban đầu dưới dạng phác thảo,
sau đó được chỉnh sửa bằng kinh nghiệm của người kỹ sư cũng như khả năng trợ giúp thông
minh của phần mềm thiết kế.Khác với các bản vẽ trên giấy, người thiết kế có thể xem mô
hình thiết kế trên máy tính từ mọi góc độ, dễ dàng thay đổi mọi chi tiết và quan sát hiệu ứng
của sự hiệu chỉnh đó.

Giao diện Người - Máy


Ngày nay hầu hết các chương trình ứng dụng trên PC đều có giao diện với người dùng dựa
trên hệ thống tương tác đồ họa: Cửa sổ, Biểu tượng, Con trỏ chuột, Menu .... Giao diện đồ
họa thực sự mang lại sự thoải mái cho người sử dụng

Biểu diễn thông tin


Các trình ứng dụng sử dụng công cụ đồ họa để tạo ra các biểu đồ, đồ thị ... minh họa tương
quan giữa các đối tượng trong kinh doanh, khoa học, các dữ liệu tài chính, thống kê ... Các
máy tính, máy ATM, máy bán hàng, máy bán vé tàu ... ở nơi công cộng đều sử dụng giao
diện đồ họa để biểu diễn những mục thông tin hướng dẫn khách hàng

Giải trí, nghệ thuật


Đối với các nhà tạo mẫu, người chụp ảnh, những chương trình trợ giúp thiết kế mẫu hay
chỉnh sửa ảnh như PhotoShop, 3DMax, ... đã giúp họ thiết kế các hình ảnh sống động. Đồ
họa máy tính cung cấp phương tiện cho các nhà làm phim tạo ra những bộ phim nổi tiếng
như Công viên Khủng long, Xác ướp Ai cập ... nhờ những kỹ xảo điện ảnh thực hiện trên
máy tính

Giáo dục và đào tạo


Đồ họa máy tính cũng góp phần quan trọng trong nghiên cứu các thực thể trừu tượng, mô
phỏng cấu trúc vật thể, tiến trình của các phản ứng hóa học, hạt nhân, hoạt động của các hệ
thống sinh lý. Trong đào tạo, các ứng dụng mô phỏng được dùng để kiểm tra trình độ người
lái, huấn luyện phi công, điều khiển giao thông ...

Bản đồ học, nghiên cứu địa lý


Đồ họa máy tính được sử dụng để tạo ra các sơ đồ địa lý và các đối tượng tự nhiên một cách
chính xác từ những số liệu đo được. Ví dụ như bản đồ địa lý, bản đồ thời tiết, bản đồ mật độ
dân số, sơ đồ khoan thăm dò, biểu đồ hải dương học.

http://www.ebook.edu.vn 3
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chương II: Công cụ đồ họa của Turbo Pascal (TP)

1. Giới thiệu

- Thiết bị phần cứng điều khiển việc hiển thị hình ảnh lên màn hình có tên là Video Card
(chúng ta hay gọi là “card màn hình”).

- Có nhiều loại Card màn hình với khả năng mạnh yếu khác nhau, mỗi loại cần driver (trình
điều khiển) riêng. Bảng sau là các file driver của TP.

File driver Kiểu Video card Chúng ta sẽ


CGA IBM CGA , chỉ hiển thị được 4 màu chỉ dùng loại
HERC.BGI HERCULES MONOCHROME, 2 màu mạnh nhất
EGAVGA.BGI VGA và đại đa số các card màn hình này
hiện nay.
Có 16 màu. Độ phân giải 640 * 480

2. Phải làm gì để khởi tạo chế độ đồ họa ?

Chúng ta sẽ lập trình đồ họa bằng TP. Muốn vậy cần phải:

- Có các file: EGAVGA.BGI, GRAPH.TPU (thư viện chứa các lệnh vẽ đồ họa) và các
file cơ bản của TP.
- Đặt chúng ở cùng 1 thư mục (nếu không thì phải lập đường dẫn cho GRAPH.TPU tại
Option/Directory/Unit directory và cho EGAVGA.BGI bằng InitGraph)
- Đặt lệnh khởi tạo chế độ đồ họa (InitGraph) vào trong chương trình

Ví dụ: Cách đơn giản và hay dùng nhất để khởi tạo đồ họa

Uses Graph;
Var hằng đ/n
gd,gm: integer; sẵn
Begin
xâu rỗng
gd:=detect;
InitGraph(gd,gm,”);
..........
..........
.......... /* Các lệnh đồ họa vẽ, xóa ... */
CloseGraph; /* kết thúc đồ họa, quay về chế độ màn hình văn bản bình thường */
End.

Vì sao lại là “đơn giản và hay dùng nhất” ?


- Không cần gõ vị trí tệp BGI
- Không cần nhớ bảng giá trị các chế độ màn hình (có khoảng hơn 10 cặp giá trị khác
nhau tương ứng với các chế độ màn hình khác nhau như EGA, HERCULES, VGA
...)
http://www.ebook.edu.vn 4
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
- Luôn luôn khởi tạo được chế độ mạnh nhất VGA (16 màu, độ phân giải 640 * 480).
Trong các phần tiếp theo ta luôn giả thiết rằng chế độ đồ họa là VGA

Chỉ để tham khảo: bảng các loại graphics card và chế độ đồ họa tương ứng

GraphDriver GraphMode Số dòng, cột


CGA CGA0 320 * 200
--- CGAHi 640 * 200
EGA EGALo 640 * 200
--- EGAHi 640 * 350
VGA VGALo 640 * 200 Chúng ta sẽ
--- VGAMed 640 * 350 chỉ dùng loại
--- VGAHi 640 * 480 mạnh nhất
HercMono HercMonoHi 720 * 348 này
... ... ...
có tổng cộng 8 giá có tổng cộng 30 giá
trị GraphDriver trị GraphMode khác
khác nhau nhau

3. Hệ trục tọa độ màn hình

(639,0)
(0,0)

(0,479) (639,479)

Trong chế độ đồ họa, chúng ta phải làm việc với một hệ trục tọa độ khác thường:
1) Trục tung Oy quay xuống dưới (hệ trục Decac nghịch)
2) các giá trị tọa độ phải là các số nguyên
3) Nếu tọa độ vượt ra ngoài khoảng (0,639) đối với hoành độ và (0,479) đối với tung
độ, thì những gì ta vẽ sẽ không hiển thị trên màn hình

Giải thích:
1) Do cấu tạo của màn hình, ta phải chấp nhận.
2) Màn hình chia thành nhiều ô vuông nhỏ (pixel) sắp xếp theo từng dòng và cột như
hình vẽ.
3) Giả sử ta vẽ đoạn thẳng AB, thì chỉ có đoạn CD nằm trong màn hình được hiển thị

http://www.ebook.edu.vn 5
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

B
D

C
Màn hình

Chú ý: chúng ta không cần nhớ 2 giá trị 640 và 480 vì TP đã có 2 hàm GetMaxX và
GetMaxY, chúng trả lại giá trị lớn nhất của hoành độ và tung độ đối với mode đồ họa hiện
thời: GetMaxX = 639 ; GetMaxY = 479 ;

0,0 1,0 2,0 ... 639,0

0,1
0,2
...
mỗi điểm ảnh là
1 ô vuông

0,479

4. Bảng màu

Với mode đồ họa VGA, bảng màu gồm 16 màu được đánh số từ 0 đến 15 như trong bảng
sau. Ta có thể dùng số thứ tự hoặc tên hằng số chỉ màu

Giá trị số Tên hằng số Màu


0 Black Đen
1 Blue Xanh da trời
2 Green Xanh lá cây
3 Cyan Xanh cẩm thạch
4 Red Đỏ
5 Magenta Tía
6 Brown Nâu
7 LightGray Xám nhạt
8 DarrkGray Xám đậm
9 LightBlue Xanh da trời nhạt

http://www.ebook.edu.vn 6
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
10 LightGreen Xanh lá cây nhạt
11 LightCyan Xanh cẩm thạch nhạt
12 LightRed Đỏ tươi
13 LightMagenta Tía nhạt
14 Yellow Vàng
15 White Trắng

5. Vẽ điểm

PutPixel(x,y,c); /* x,y : integer ; c: word (kiểu số nguyên dương) */


Vẽ 1 điểm ảnh tại tọa độ (x,y) với màu c,
GetPixel(x,y):word
Hàm GetPixel trả lại một số nguyên dương là màu của điểm ảnh ở tọa độ (x,y), nói cách
khác nó cho biết màu của pixel(x,y) là màu gì.

Ví dụ: Tô toàn màn hình bằng màu đỏ

Uses Graph;
Var
gd,gm: integer;
i,j:integer;
Begin
gd:=detect;
InitGraph(gd,gm,”);
for i:=0 to GetMaxX do
for j:=0 to GetMaxY do
PutPixel(i,j,red) ;
Readkey;
/* Gặp readkey chương trình sẽ dừng lại để ta quan sát màn hình. Xem xong ta bấm
phím bất kỳ để qua lệnh này */

CloseGraph;
End.

VNhững hằng, biến nào trong chương trình trên có thể được thay bằng những giá trị tương
đương mà không làm thay đổi chương trình ?
VViết chương trình tô một phần tư màn hình (phía trên bên phải) bằng màu xanh da trời
VChương trình trên lấp kín màn hình bằng cách tô theo dòng hay cột ?

http://www.ebook.edu.vn 7
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
Ví dụ: vẽ lưới điểm nhấp nháy

uses crt,graph;
var
gd,gm,i,j:integer;
x,y:integer;
begin
gd:=detect; initgraph(gd,gm,'');
randomize; /* khởi tạo bộ sinh số ngẫu nhiên */

repeat
x:=random(100); y:=random(100); Hàm trả lại số màu
if GetPixel(x,y) <>0 then hiện có (16)
Putpixel(x,y,0)
else PutPixel(x,y,random(GetmaxColor));
delay(2);
Until Keypressed;
closegraph;
end.

VHàm GetPixel làm chức năng gì trong ví dụ trên ?


VThử thay đổi giá trị tham số của hàm delay() và random() và quan sát kết quả

Ví dụ: Vẽ bầu trời sao đơn giản

uses crt,graph;
var gd, gm, i : integer;
BEGIN
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
for i := 1 to 1000 do
putpixel(random(640),random(480),random(15)+1);
readkey;
END.

VHãy phối hợp những kỹ thuật trong 2 ví dụ trên ( hàm random, vòng lặp Repeat, lệnh
GetPixel để tạo ra bầu trời sao đẹp hơn

Ví dụ: Vẽ đồ thị hàm số y=sin(x)

Uses crt,graph;
Var
tx,ty,gd,gm,i,j:integer;
d,x,y:real;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
setviewport(getmaxX div 2,getmaxY div 2,getmaxX,getmaxY,clipoff);

http://www.ebook.edu.vn 8
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
d:=0.001; x:=0; tx:=20; ty:=40;
while x<4*pi do
begin
putpixel(round(tx*x),-round(ty*sin(x)),yellow);
x:=x+d;
end;
readln;
closegraph;
End.

VHãy giải thích ý nghĩa của tx,ty,d ?


VNếu gán d:=0.5 thì kết quả thay đổi ra sao ?
VVì sao phải có dấu trừ trong tham số thứ 2 của PutPixel ? Nếu bỏ dấu trừ đi thì kết quả ra
sao ?
VHãy vẽ đồ thị hàm số y = x2 – 2x +1 trong khoảng [-3,3]
VHãy vẽ đồ thị hàm số y = sin 2x trong khoảng [-2π, 2π]

6. Vẽ đoạn thẳng

Line(x1,y1,x2,y2) /* x1,x2,y1,y2: integer */

Vẽ đoạn thẳng nối (x1,y1) với (x2,y2) bằng màu vẽ hiện thời ấn định bởi lệnh SetColor gần
nhất. Nếu không có lệnh SetColor nào thì màu vẽ mặc định luôn là màu Trắng (white).

Trước lệnh vẽ đoạn thẳng ta nên đặt màu vẽ cho lệnh Line bằng lệnh

SetColor (c); /* c: word */

VHãy vẽ thêm 2 trục tọa độ cho ví dụ mẫu vẽ đồ thị hàm sin ở mục trên
VHãy làm lại ví dụ “Tô toàn màn hình bằng màu đỏ” nhưng dùng lệnh Line thay cho
PutPixel
VHãy tô kín hình chữ nhật (50,50,100,100) bằng cách dùng lệnh Line
50,50

100,100

VVẽ và lấp đầy một hình bình hành bằng các đoạn thẳng xiên như hình (a). Có thể lấp đầy
bằng các đoạn thẳng nằm ngang như hình (b) được không ?

http://www.ebook.edu.vn 9
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

(a) (b)

VBiết rằng trên màn hình màu đen chỉ có 1 tam giác màu trắng có vị trí và hình dạng bất
kỳ. Hãy đếm xem có bao nhiêu điểm ảnh nằm bên trong tam giác đó (không tính các cạnh) ?

VHãy vẽ lại đồ thị hàm y = sin(x) nhưng thay vì chấm từng điểm ảnh như ở ví dụ trên thì
ta nối điểm ảnh này với pixel tiếp theo.

Ngoài ra còn có 2 lệnh vẽ đoạn thẳng khác


LineTo(x,y) /* x,y: integer */
LineRel(dx,dy) /* x1,x2,y1,y2: integer */

Lệnh LineTo(x,y) vẽ đoạn thẳng nối CP hiện thời (xem khái niệm CP ở phần sau) với điểm
(x,y), nói cách khác
Line(x1,y1,x2,y2);
tương đương với 2 lệnh:
MoveTo(x1,y1); LineTo(x2,y2);
Còn LineRel(dx,dy) vẽ đoạn thẳng từ CP đến 1 điểm có độ chênh là (dx,dy), nói cách khác:
LineRel(dx,dy)
tương đương với
Line(GetX,GetY,GetX+dx,GetY+dy);
Thiết lập dạng đoạn thẳng
SetLineStyle(dạng,mẫu-tự-tạo,bềdày); { ta bỏ qua mẫu_tự_tạo bằng cách cho 1 giá trị
nguyên tùy ý}
Dạng:

SolidLn 0 Nét Đặc


DottedLn 1 Nét chấm chấm

http://www.ebook.edu.vn 10
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
CenterLn 2 Nét chấm gạch
DashedLn 3 Nét đứt đoạn

Bề dày có thể nhận giá trị từ 1 (bình thường) đến 3 (nét đậm).

7. Thiết lập chế độ vẽ đè

SetWriteMode (mode); /* mode: word */

Mode Giá trị số Tác dụng


CopyPut 0 Vẽ hình mới đè lên hình cũ (chế độ vẽ bình thường)
XorPut 1 Màu của từng pixel sẽ được Xor với màu cũ

Trong chế độ XorPut, giá trị màu vẽ và màu nền được nhị phân hóa, sau đó làm phép Xor
với nhau để ra màu hiển thị.

Xor 0 1
0 0 1
1 1 0

Lệnh SetWriteMode có tác động tới các lệnh vẽ đường như: Line, LineTo, LineRel,
Rectangle, DrawPoly ... và không tác động tới các lệnh vẽ đường tròn, elip ...

Ví dụ: Minh họa chế độ xorput

Uses Graph;
Var
gd,gm: integer;
i,j:integer;
Begin
gd:=detect;
InitGraph(gd,gm,”);
SetFillStyle(1,Brown); /* đặt chế độ tô đặc với màu tô là nâu */
Bar(100,100,200,200); /* Vẽ hình vuông màu nâu */
Readkey;

SetColor(white);
SetWriteMode(XorPut);
for i:=100 to 200 do line(100,i,200,i) ; /* hình vuông đổi thành màu gì ? */
Readkey;

CloseGraph;
End.

VSau lệnh Readkey thứ nhất chương trình dừng lại, lúc đó trên màn hình có gì ?
VSau lệnh Readkey thứ 2 chương trình dừng lại, lúc đó trên màn hình có gì ? Tại sao ?

http://www.ebook.edu.vn 11
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chế độ XorPut đặc biệt hay được dùng để vẽ hình chuyển động vì dù hình mới là gì thì sau
2 lần vẽ đè với XorPut hình cũ cũng sẽ được khôi phục nguyên trạng (vẽ hình chuyển động
không để lại vết)

VGiải thích nhận định trên


8. Cửa sổ ViewPort của TP

ViewPort (của đồ họa Pascal) là 1 vùng hình chữ nhật trên màn hình. Để thiết lập ViewPort
ta dùng lệnh:

SetViewPort(x1,y1,x2,y2,clip);

x1,x2,y1,y2: tọa độ của ViewPort; clip = true (không cho phép vẽ ra ngoài) hoặc false.
Chú ý là sau khi đã thiết lập ViewPort thì gốc tọa độ được tự động chuyển về (x1,y1).

ViewPort: clip=off ViewPort: clip=on

Xóa nội dung bên trong ViewPort: ClearViewPort;


Loại bỏ hẳn ViewPort, trở về chế độ làm việc toàn màn hình: ClearDevice; Lệnh này cũng
dùng để xóa màn hình và đưa CP về (0,0)

9. Con trỏ trong chế độ đồ họa (CP: Current Pointer)

Ta không nhìn thấy CP trên màn hình, nhưng TP luôn theo dõi vị trí của CP bằng cặp hàm
GetX, GetY: trả lại tọa độ hiện thời của CP
Moveto(x,y): di chuyển CP tới (x,y)
MoveRel(dx,dy): di chuyển CP tới vị trí mới cách vị trí cũ 1 độ chênh là (dx,dy)
dx
x
O

Moverel (dx,dy)
dy (x1,y1)

(x2,y2)
y
http://www.ebook.edu.vn 12
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Lệnh có liên quan đến CP:


- LineTo(x,y): vẽ đoạn thẳng nối từ CP đến (x,y), đồng thời chuyển CP đến đó.
- LineRel(dx,dy): vẽ đoạn thẳng nối từ CP đến vị trí mới có độ chênh là (dx,dy) và
kéo CP tới đó.

10. Vẽ hình chữ nhật


Vẽ hình chữ nhật có đỉnh trên bên trái là (x1,y1), đỉnh dưới phải (x2,y2) và các cạnh song
song với 2 trục:
Rectangle(x1,y1,x2,y2); /* x1,y1,x2,y2: integer */

Để vẽ và tô hình chữ nhật đặc ta dùng Bar(x1,y1,x2,y2); /* x1,y1,x2,y2: integer */


màu tô và mẫu tô phải được thiết lập từ trước bằng lệnh
SetFillStyle(Pattern, Color);

Pattern Giá trị số Mẫu tô


EmptyFill 0 Màu nền (= để trống)
SolidFill 1 Màu đặc
LineFill 2 Gạch dọc
LtSlashFill 3 Tô sọc chéo thưa
Slashfill 4 Tô sọc chéo dày
.... ...
UserFill 12 người lập trình tự định nghĩa bằng lệnh SetFillPattern()

Lệnh SetFillStyle() đặt mẫu tô cho các lệnh tô hình kín như:
• Rectangle: hình chữ nhật
• Bar: hình chữ nhật đặc
• Bar3D: hình hộp
• FillPoly: đa giác
• PieSlice: quạt tròn

Ví dụ: Vẽ bàn cờ

uses crt,graph;
const stop=50;
var

http://www.ebook.edu.vn 13
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
gd,gm,i,j,cạnh,a,màu:integer;

Begin
canh:=40;
a:= 100;
gd:=detect; initgraph(gd,gm,'');
màu:=white;
setlinestyle(1,1,3);
rectangle(a,a,a+8*canh,a+8*canh); {vẽ khung bàn cờ bằng đường đứt đoạn}
for i:=0 to 7 do
for j:=0 to 7 do
begin
setfillstyle(1,mau);
bar(a+i*canh,a+j*canh,a+(i+1)*canh,a+(j+1)*canh); {1}
if j<>7 then {ô dưới cùng của một cột}
if mau=white then mau:= black else mau:=white; {2}
end;
readkey;
closegraph;
end.

VGiải thích ý nghĩa của biến a, canh, i,j trong chương trình trên ? Các lệnh {1}, {2} có tác
dụng gì ?
VĐoạn trình sau có vẽ được bàn cờ không ?
for i:=0 to 7 do
for j:=0 to 7 do
begin
if (i+j) mod 2 =0 then mau:=white else mau:= black;
setfillstyle(1,mau);
bar(a+i*canh,a+j*canh,a+(i+1)*canh,a+(j+1)*canh);
end;

VVẽ các hình chữ nhật có vị trí và kích thước ngẫu nhiên (có các cạnh nằm ngang hoặc
thẳng đứng như hình (a)
VVẽ các hình chữ nhật ngẫu nhiên (các cạnh có thể nghiêng tùy ý kiểu như hình (b)

(b)
(a)

http://www.ebook.edu.vn 14
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
VHãy vẽ một hình vuông ở tâm màn hình, cho nó từ từ phình to ra đến khi chạm rìa màn
hình thì dừng lại. Sau đó co lại để trở về kích thước ban đầu.

11. Đa giác

Vẽ đa giác
DrawPoly(n,P);
n: số đỉnh đa giác +1
P: tham số chứa tọa độ các đỉnh của đa giác

Tô đa giác bằng lệnh sau:


FillPoly(n,P); /* n và P như trên. Chú ý là n không cần cộng 1*/
Xem các ví dụ sau để hiểu rõ

Ví dụ: Vẽ các ngũ giác ngẫu nhiên

Uses crt,graph;
Type
Dinh = Record /* Đỉnh đa giác */
x,y:integer;
End;

Var
gd,gm:integer;
i:integer;
dagiac: array[1..6] of Dinh;
Begin
gd:=detect;
InitGraph(gd,gm,'');
Randomize;
Repeat
SetColor(random(GetMaxColor)); /* màu được chọn ngẫu nhiên */

http://www.ebook.edu.vn 15
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
for i:=1 to 5 do
begin
dagiac[i].x:=random(getMaxX); /* tọa độ đỉnh được chọn ngẫu nhiên */
dagiac[i].y:=random(getMaxY);
end;
dagiac[6]:=dagiac[1];
DrawPoly(6,dagiac);
Delay(1000);
Until KeyPressed;
CloseGraph;
End.

Chú ý lệnh dagiac[6]:=dagiac[1] . Để vẽ đa giác kín N đỉnh ta phải tạo ra đỉnh thứ N+1
trùng với đỉnh đầu.

VCác đa giác trong chương trình trên đè chồng lên nhau và làm đầy màn hình. Hãy sửa
chương trình để chúng hiện lên rồi tự tắt. Hãy sửa để luôn luôn lưu lại trên màn hình 3 đa
giác mới nhất.

Ví dụ: Vẽ và tô các ngũ giác ngẫu nhiên


Uses crt,graph;
Type
Dinh = Record
x,y:integer;
End;

Var
gd,gm:integer;
i:integer;
dagiac: array[1..6] of Dinh;
Begin
gd:=detect;
InitGraph(gd,gm,'');
Randomize;
Repeat
SetColor(random(GetMaxColor));
SetFillStyle(SolidFill,random(GetMaxColor));
for i:=1 to 5 do
begin
dagiac[i].x:=random(getMaxX);
dagiac[i].y:=random(getMaxy);
end;
dagiac[6]:=dagiac[1];
DrawPoly(6,dagiac);
FillPoly(6,dagiac);
Delay(2000);
Until KeyPressed;
CloseGraph;
http://www.ebook.edu.vn 16
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
End.

Chú ý quan sát ta thấy, với các đa giác lõm lệnh FillPoly tính toán tất cả các chỗ tự cắt và
sau đó tô riêng từng phần. Màu tô và mẫu tô xác định bởi SetFillStyle. Dưới đây là 1 ngũ
giác lõm với các cạnh tự cắt được tô bởi FillPoly

12. Tô màu miền kín

FloodFill(x,y,color); /* x,y : integer; c: word */


Vùng cần tô được nhận dạng nhờ 2 yếu tố:
- đường biên khép kín có màu color
- điểm (x,y) là một điểm bất kỳ nằm bên trong vùng cần tô.
Màu tô và mẫu tô được ấn định bởi SetFillStyle
(x,y)
(x,y)

Ví dụ: VẼ LÁ CỜ ĐỎ SAO VÀNG


uses crt,graph;
var gd, gm, i, goc, r : integer;
p : array[1..5,1..2] of integer; { toạ độ các đỉnh ngôi sao }
BEGIN
gd := 0; initgraph(gd,gm,'');

goc := 18; r := 100;


for i := 1 to 5 do begin
p[i,1] := round(r*cos(goc*pi/180)); { hoành độ của đỉnh thứ i }
p[i,2] := - round(r*sin(goc*pi/180)); { tung độ của đỉnh thứ i }
goc := goc + 2*72;
end;

http://www.ebook.edu.vn 17
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

SetFillStyle(1,red); {vẽ lá cờ là hình chữ nhật màu đỏ}


Bar(100,100,540,380);

SetViewPort(320,240,600,400,false); {chuyển gốc toạ độ ra giữa màn hình}


SetColor(yellow);
SetFillStyle(1,yellow);
FillPoly(5,p); {2 lệnh này tô hình ngôi sao vàng }
FloodFill(0,0,yellow);
readkey;
END.

V Vì sao trong công thức tính tung độ đỉnh thứ i của ngôi sao lại có dấu trừ ? Nếu bỏ dấu
trừ này đi thì hiện tượng gì xảy ra ?
V Vì sao phải cần 2 lệnh mới tô được ngôi sao ? Nếu bỏ lệnh FloodFill đi thì kết quả sẽ ra
sao ? Hoặc nếu chỉ bỏ đi lệnh FillPoly thì trên màn hình sẽ có gì ?
VLệnh FillPoly ở trên tô màu một ngũ giác, đó là ngũ giác nào ?
VGiải thích các lệnh: goc := 18; goc := goc + 2*72;
VVì sao không vẽ và tô đa giác 10 đỉnh (123456789-10) ? thay vào đó ví dụ trên vẽ đa
giác nào ?

y
A 1

B E 3 2 10
180 9
O 4 8
x
C D 6
5 7

13. Vẽ cung, đường tròn


A
Vẽ cung tròn: Arc(x,y, g1,g2,r); g2 B
g1
x,y: integer - tọa độ tâm đường tròn
g1,g2: word – góc bắt đầu và góc cuối O
của cung tròn (tính bằng độ)
r: word – bán kính

Để vẽ hình quạt tròn, đầu tiên ta vẽ cung tròn, sau đó gọi thủ tục
GetArcCoords(VAR ArcCoords: ArcCoodsType);
để lấy tọa độ 2 đầu mút (A,B) của cung.Cuối cùng ta vẽ hai đoạn thẳng nối chúng với tâm O
của đường tròn

Với kiểu ArcCoodsType được định nghĩa như sau:


Type
http://www.ebook.edu.vn 18
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
ArcCoodsType = RECORD
x,y:integer;
xStart,yStart:integer;
xEnd,yEnd:integer;
END
trong đó (x,y) là tọa độ tâm O, (xStart,yStart) là tọa độ điểm đầu B của cung, (xEnd,yEnd)
là điểm cuối A.

Ví dụ: Vẽ quạt tròn

uses crt,graph;
var
gd,gm:integer;
a:ArcCoordsType;
x,y,g1,g2,r: integer;
Begin
gd:=detect; initgraph(gd,gm,'');
x:=GetMaxX div 2; y:=GetMaxY div 2; { tâm đặt chính giữa màn hình }
g1:=30; g2:=330; {góc bắt đầu, góc kết thúc }
r:=100;
arc(x,y,30,330,100);
GetArcCoords(a);
line(x,y,a.xStart,a.yStart);
line(x,y,a.xEnd,a.yEnd);
readkey;
closegraph;
End.

VCải tiến chương trình trên để vẽ đầu cá đóng - mở miệng liên tục
VViết chương trình vẽ hình trăng lưỡi liềm và khuyên

Vẽ đường tròn tâm (x,y) bán kính r :


Circle(x,y,r); /* x,y: integer; r: word */
Vẽ cung elip tâm (x,y), bán trục lớn xr, bán trục bé yr, góc bắt đầu và góc kết thúc là g1,g2
Ellipse(x,y,g1,g2,xr,yr)

http://www.ebook.edu.vn 19
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

yr

xr

Vẽ và tô hình quạt tròn:


PieSlice(x,y, g1,g2, r);
Ý nghĩa các tham số giống như lệnh Arc

Để tô màu ellip, cũng như đường tròn, ta dùng thủ tục:


FillEllipse(x,y,xr,yr); {x,y:integer; xr,yr: word}

Để tô một cung ellip ta gọi thủ tục


Sector(x,y,StAngle,EndAngle,xr,yr); {x,y: integer; StAngle,EndAngle, xr,yr: word}

Ví dụ: VẼ BÓNG CHUYỂN ĐỘNG KIỂU BẬT TƯỜNG


uses crt,graph;
var gd,gm,x,y,dx,dy,r : integer;
BEGIN
gd := 0; initgraph(gd,gm,'');
x := 100; y := 100; dx := -6; dy := 5; r := 30;
repeat
setcolor(yellow);
circle(x,y,r); {vẽ đường tròn màu vàng}
delay(20);
setcolor(0);
circle(x,y,r); {vẽ đường tròn màu trùng màu nền <=> xoá }
http://www.ebook.edu.vn 20
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

if (x>=640-r) or (x<r) then dx:=-dx; {nếu chạm cạnh trái/phải thì đổi hướng}
if (y>=480-r) or (y<r) then dy:=-dy; {nếu chạm cạnh trên/dưới thì đổi hướng}
x := x + dx; y := y + dy; {cập nhật toạ độ}
until keypressed; {có phím nhấn thì dừng}
END.

VVị trí xuất phát, kích thước bóng là gì ? biến nào quy định hướng xuất phát của bóng ?
VChương trình trên dùng kỹ thuật gì để vẽ hình chuyển động ?
VLàm sao để tăng/giảm tốc độ bóng ?
Ví dụ: Vẽ đồng hồ với kim giây chuyển động
Uses crt,graph;
Var
gd,gm:integer;
x,y,a,b,r:integer;
c,i,x1,x2,y1,y2:integer;
g,d:real;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
a:=GetMaxX div 2; b:=GetmaxY div 2;
Setcolor(Yellow);
SetWriteMode(Xorput);
r:=150;
Circle(a,b,r);
{Vẽ các vạch chia}
c:=5; {chiều dài ½ vạch chia}
d:=pi/6; g:=0;
while g< 2*pi do
begin
g:=g+d;
x1:=a+round((r-c)*cos(g)); x2:=a+round((r+c)*cos(g));
y1:=b-round((r-c)*sin(g)); y2:=b-round((r+c)*sin(g));
line(x1,y1,x2,y2); {Vẽ vạch chia}
end;
{Vẽ kim giây chuyển động}
x:=a; y:=b-r; line(a,b,x,y);
g:=pi/2; d:=pi/30;
repeat
line(a,b,x,y);
g:=g-d;
x:=round(a+r*cos(g)); y:=round(b-r*sin(g));
line(a,b,x,y);
delay(1000);
until KeyPressed;
closegraph;
End.

http://www.ebook.edu.vn 21
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

VÝ nghĩa các biến a,b,x,y, r, d là gì ?


VChương trình trên dùng kỹ thuật gì để vẽ kim giây chuyển động ?
VNếu là vẽ kim phút thì phải sửa chương trình trên như thế nào ?
VHãy vẽ đồng hồ với 2 kim cùng chuyển động: kim giây và kim 1/10 giây

14. Viết chữ (x,y)


OutText(s); {s: string} ABCDEFG
OutTextXY(x,y,s); {x,y:integer; s: string}

Lệnh OutText(s) hiển thị xâu ký tự s tại vị trí CP, không di chuyển CP. Lệnh OutTextXY
hiển thị xâu ký tự s tại vị trí (x,y)

Các phông chữ (font) khác nhau nằm trên các file *.CHR, nên để chúng tại cùng vị trí với
file *.BGI. Chọn kiểu font chữ bằng lệnh sau:

SetTextStyle(Font, Direction, Size);

Tham số font nhận các giá trị sau Tham số Direction nhận các giá trị sau

Tên font Giá trị số Chiều viết Giá trị Tác dụng
DefaultFont 0 số
TriplexFont 1 HorizDir 0 viết ngang
SmallFont 2 VertDir 1 viết theo chiều
SansSerifFont 3 thẳng đứng
GothicFont 4

Hệ số phóng to Size nhận các giá trị từ 1 đến 10.

Ví dụ: Vẽ chữ có bóng


uses crt,graph;
Var
gd,gm,i:integer;

Begin
gd:=detect; initgraph(gd,gm,'');
setTextStyle(GothicFont,0,10);
SetColor(DarkGray); {1}
for i:=1 to 10 do outTextxy(100+i,100-i,'Graphic');
SetColor(LightGray); {2}
outTextxy(100,100,'Graphic');
readln;

http://www.ebook.edu.vn 22
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
closegraph;
End.

VMàu chữ và màu bóng có giống nhau không ? giải thích tác dụng của lệnh {1} và {2} ?
nếu hoán vị 2 lệnh đó thì sao ?
VLàm sao để điều khiển chữ đổ bóng sang hướng trái/phải, lên trên/xuống dưới như các
hình dưới đây?

VViết chương trình để các dòng chữ chuyển động từ hai bên ra giữa / rơi từ trên xuống ...
15. Cắt dán hình

Để lưu một hình vào bộ nhớ, ta phải lưu cả diện tích hình chữ nhật bao nó
Memory
(x1,y1)

ABC (x2,y2)

Để tính toán kích thước vùng nhớ cần dùng để chứa hình, ta gọi hàm
ImageSize(x1,y1,x2,y2) ; {x1,y1,x2,y2: integer }

với (x1,y1,x2,y2) là tọa độ hình chữ nhật bao quanh hình cần lưu trữ. Chú ý là TP không
cho phép lưu trữ một hình có diện tích quá lớn.

Sau đó, ta xin trình dịch cấp phát vùng nhớ này bằng cách gọi thủ tục

GetMem(p: pointer, n: word) ;

Thủ tục này xin cấp phát 1 vùng nhớ n byte (n phải được dự trù trước bằng cách gọi hàm
ImageSize), rồi lưu địa chỉ vùng nhớ đó vào con trỏ p. Chú ý: sau khi dùng xong nên giải

http://www.ebook.edu.vn 23
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
phóng vùng nhớ này bằng FreeMem(p,n); nếu không sau vài lần gọi GetMem sẽ cạn dung
lượng nhớ.

Bước tiếp theo, ta dùng thủ tục

GetImage(x1,y1,x2,y2, p) ; {x1,y1,x2,y2: integer ; p: pointer}

để sao chép các điểm ảnh trên màn hình nằm trong phạm vi hình chữ nhật (x1,y1,x2,y2) vào
vùng nhớ xác định bởi con trỏ p;

Khi cần thiết, ta dán ảnh đang lưu trong bộ nhớ ra màn hình bằng thủ tục

PutImage(x,y,p,mode); {x,y: integer; p: pointer; mode: word}

Lệnh này sẽ copy ảnh đang lưu trong bộ nhớ xác định bởi p vào vị trí (x,y) theo kiểu mode
Tham số mode nhận các giá trị như sau

Mode Giá trị số Tác dụng


CopyPut 0 Vẽ hình mới đè lên hình cũ
XorPut 1 Màu của từng pixel sẽ được Xor với màu cũ

Ví dụ: Cắt dán ảnh

uses crt,graph;
var
gd,gm:integer;
i,x,y,dx,dy,canh:integer;
p:pointer; {con trỏ trỏ tới vùng nhớ dùng để cất giữ ảnh}
size:word;
Begin
gd:=detect; initgraph(gd,gm,'');

http://www.ebook.edu.vn 24
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
randomize;
dx:= GetMaxX div 2; dy:= GetMaxY div 2;
SetViewPort(0,0,dx,dy,true);
for i:=1 to 40 do {Vẽ các vòng tròn ngẫu nhiên trong phần tư màn hình trên bên trái}
begin
x:=random(dx); y:=random(dy);
SetColor(random(GetMaxColor));
circle(x,y,random(dy));
end;

SetViewPort(0,0,GetMaxX,GetMaxY,false);
SetColor(White);
x:=50; y:=50; canh:=100; {ảnh cần lưu là 1 hình vuông cạnh dài 100 pixel}
Rectangle(x,y,x+canh,y+canh); {vẽ đường bao quanh phạm vi ảnh cần lưu}
Size:=ImageSize(x,y,x+canh,y+canh);
GetMem(p,size);
GetImage(x,y,x+canh,y+canh,p^);
PutImage(x+dx,y,p^,CopyPut);
readkey;
closegraph;
End.
VGiải thích ý nghĩa của các biến: canh,x,y. Tác dụng của 2 lệnh SetViewPort trong
chương trình trên là gì ? thử thay đổi giá trị tham số cuối cùng (tham số boolean) của chúng
và quan sát kết quả
VNếu thay CopyPut bằng XorPut trong lệnh PutImage(x+dx,y,p^,CopyPut); thì có gì thay
đổi không ? Vì sao ?

16. Nhận biết phím được ấn

Trong khi chương trình đang chạy, người dùng có thể ấn các phím để điều khiển (ví
dụ trong các game sử dụng bàn phím để điều khiển hành động của nhân vật). Để nhận biết
phím nào được ấn, một trong những kỹ thuật TP hay sử dụng là dùng hàm Readkey. Đối với
những phím đặc biệt như các phím mũi tên, lần đọc bằng Readkey thứ nhất sẽ trả lại giá trị
0 để ta nhận biết đó là phím mở rộng, lần Readkey thứ hai mới đọc ra mã quét mở rộng của
chúng phím đó. Đối với phím bình thường (như Esc, các phím chữ cái ... ) thì chỉ cần một
lần đọc bằng Readkey.

Ví dụ: Hộp chuyển động theo sự điều khiển của người dùng

{Hộp vuông dịch chuyển theo phím mũi tên mà người dùng bấm}
Uses crt,graph;
Var
gd,gm:integer;
canh,x,y,d:integer;
ch:char;
Procedure hộp(x,y:integer);
Begin
rectangle(x-canh,y-canh,x+canh,y+canh); {Vẽ hộp}
http://www.ebook.edu.vn 25
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
delay(d);
rectangle(x-canh,y-canh,x+canh,y+canh); {Xóa hộp}
End;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
x:=100; y:=100; {Vị trí ban đầu của hộp }
setWriteMode(xorput);
d:=50; canh:=10;
Repeat
Repeat
hộp(x,y);
Until Keypressed;
ch:=readkey;
if ch=#0 then {một phím mở rộng đã được ấn }
begin
ch:=readkey;
case ch of
#72: y:=y-10; {phím Ç }
#80: y:=y+10; {phím È }
#75: x:=x-10; {phím Å }
#77: x:=x+10; {phím Æ }
end;
end;
Until ch=#27; {phím ESC}
closegraph;
End.

VGiải thích ý nghĩa của các biến: canh, ch, x,y


VChương trình trên dùng kỹ thuật gì để vẽ hộp chuyển động ?
VChương trình trên quy định phím nào là phím kết thúc chương trình ? Hãy viết lại
chương trình để nó coi phím chữ a là phím kết thúc (mã ASCII của chữ a là 65)
VQuan sát ta thấy nếu hộp di chuyển ra ngoài màn hình thì nó biến mất. Hãy sửa chương
trình để nó không thể chạy vượt ra khỏi phạm vi màn hình (dừng lại khi ra đến mép, hoặc
chạm vào mép và bắt đầu chạy ngược lại)

17. Các kỹ thuật đồ họa cơ bản và minh họa

http://www.ebook.edu.vn 26
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
Ví dụ: VẼ BÁNH XE LĂN (1)

uses crt,graph;
var gd,gm,x,y,dx,da,r,a : integer;

procedure banhxe(x,y,r,c,n,a : integer); {vẽ bánh xe có n nan hoa với màu c}


var goc,dx,dy,i : integer; {a là góc của nan hoa đầu tiên}
begin
SetColor(c); goc := a;
circle(x,y,r);
for i := 1 to n do begin
dx := round(r* cos(goc * pi/180)); {dx, dy là toạ độ tương đối của đầu nan hoa}
dy :=-round(r* sin(goc * pi/180));
line(x,y,x+dx,y+dy);
goc := goc + 360 div n;
end;
end;
BEGIN
gd := 0; initgraph(gd,gm,'');
x := 30; y := 200; dx := 3; a := 30; r := 30; {dx là chiều dài 1 bước tiến của bánh xe}
da:=round(dx/r*180/pi); {da là góc quay của nan hoa tương ứngvới bước tiến dx}
repeat
banhxe(x,y,r,yellow,12,a); {vẽ bánh xe}
delay(40);
banhxe(x,y,r,black,12,a); {vẽ bánh xe với màu nền để xoá}

if (x>=640-r) then x := r; {nếu bánh xe đến mép bên phải thì quay lại bên trái}
x := x + dx;
if a < 0 then a := a + 360;
a := a - da; {quay ngược chiều dương nên phải trừ}
until keypressed;

END.

http://www.ebook.edu.vn 27
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
VTrong Procedure banhxe(), dx,dy là tọa độ tương đối của đầu nan hoa trong hệ tọa độ
nào ? (gốc tọa độ ở đâu ? trục Oy hướng nào ?)

VTrong procedure banhxe, 360 div n là góc gì ? tại sao có dấu trừ trong lệnh dy :=-
round(r* sin(goc * pi/180)); tọa độ tâm bánh xe ở đâu ?

VTại sao phải gán da:=round(dx/r*180/pi); thay vào đó, nếu gán những giá trị cụ thể như
3,6,9 độ cho góc quay da thì kết quả ra sao ?

VHãy sửa chương trình để bánh xe lăn ngược lại mỗi khi chạm đến 2 biên trái/phải

VHãy dùng kỹ thuật XorPut để xóa bánh xe trong procedure banhxe

Ví dụ: Vẽ bánh xe (2)

uses crt,graph;
var
gd,gm:integer;
r,x,y,direct,buoc:integer; gia_so_goc,goc:real;

procedure ve_banh_xe;
var x1,y1,x2,y2,x3,y3:integer;
begin
x1:=x+round(r*cos(goc));y1:=y-round(r*sin(goc));
x2:=x+round(r*cos(goc+2*pi/3));y2:=y-round(r*sin(goc+2*pi/3));
x3:=x+round(r*cos(goc-2*pi/3));y3:=y-round(r*sin(goc-2*pi/3));
Circle(x,y,r); line(x,y,x1,y1);line(x,y,x2,y2);line(x,y,x3,y3);
delay(30); setcolor(0);
Circle(x,y,r); line(x,y,x1,y1);line(x,y,x2,y2);line(x,y,x3,y3); {xoa}
delay(30);
goc:=goc-gia_so_goc*direct; setcolor(yellow);
end;

begin
direct:=1; buoc:=5;
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
x:=100; goc:=0;r:=30; y:=200;
gia_so_goc:=buoc/r; setcolor(yellow);
repeat
ve_banh_xe;
if (r> x+direct*buoc) or (x+direct*buoc > getmaxX-r) then direct:=-direct;
x:=(x+direct*buoc);
until Keypressed;

closegraph;

http://www.ebook.edu.vn 28
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
end.

VÝ nghĩa các biến r,x,y,direct,buoc, gia_so_goc, goc là gì ?


VNếu muốn bánh xe lăn nhanh hơn / to hơn thì phải thay đổi giá trị biến nào

Ví dụ: Vẽ quỹ đạo chuyển động của mặt trời, trái đất và mặt trăng

uses crt,graph;
var gd,gm,x,y,x1,y1,da,da1,r,r1,goc,goc1 : integer;

procedure hinhtron(x,y,r,c : integer); {vẽ hình tròn có màu c}


var goc,dx,dy,i : integer;
begin
SetColor(c);
circle(x,y,r);
SetFillStyle(1,c);
FloodFill(x,y,c);
end;

BEGIN
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
SetViewPort(320,240,600,400,false); {chuyển gốc toạ độ ra góc}
goc := 0; goc1 := 0; {goc là góc chuyển động của Trái đất, goc1 là của Mặt trăng}
da :=360 div 360;da1 := 360 div 30; {Trái đất quay 1o 1 lần, tương ứng 1 năm 360 ngày }
hinhtron(0,0,50,lightred); {vẽ Mặt trời}
repeat
x := round(240*cos(goc*pi/180)); {toạ độ tương đối của Trái đất với Mặt trời}
y :=-round(200*sin(goc*pi/180)); {chú ý quỹ đạo hình elip}

http://www.ebook.edu.vn 29
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
hinhtron(x,y,20,lightblue); {vẽ Trái đất}
x1 := round(60*cos(goc1*pi/180));{toạ độ tương đối của Mặt trăng so với Trái đất}
y1 :=-round(50*sin(goc1*pi/180));
hinhtron(x+x1,y+y1,8,yellow); {vẽ Mặt trăng}
delay(60);

hinhtron(x,y,20,0); {xoá bằng cách vẽ bằng màu nền}


hinhtron(x+x1,y+y1,8,0);

if goc < 0 then goc := goc + 360; {cập nhật góc chuyển động}
goc := goc - da;
if goc1 < 0 then goc1 := goc1 + 360;
goc1 := goc1 - da1;
until keypressed;
END.

Ví dụ: VẼ CÁC ĐƯỜNG CONG TRONG MẶT PHẲNG 2D


uses crt,graph;
var gd, gm, xo, yo, w, h : integer;
x1,y1,x2,y2, xtl, ytl : real;
(* Khởi tạo các tham số của cửa sổ và khung nhìn *)
procedure khoitao_cuaso;
begin
xo := 20; yo := 40; w := 600; h := 400;
xtl := 50; ytl := 50; {chọn trước tỉ lệ ngang và dọc, cho bằng nhau}
x2 := w/xtl/2; x1 := -x2; {căn cửa sổ để tâm là gốc toạ độ}
y2 := h/ytl/2; y1 := -y2;
end;
{Các hàm chuyển toạ độ thực thành toạ độ màn hình}
function tox(x : real): integer;
begin
tox := xo + round((x-x1)*xtl);
end;
function toy(y : real): integer;
begin
toy := yo + round((y2-y)*ytl);
end;

{Thủ tục vẽ đoạn thẳng trong mặt phẳng thực 2D}


procedure Line2D(x1,y1,x2,y2: real);
begin
Line(tox(x1),toy(y1),tox(x2),toy(y2));
end;

{Thủ tục vẽ trục toạ độ}

http://www.ebook.edu.vn 30
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
procedure vetruc;
var i : integer;
x : string;
begin
Line2D(x1,0,x2,0); {vẽ trục x}
Line2D(x2-0.2,+0.1,x2,0); {vẽ hình mũi tên trên trục x}
Line2D(x2-0.2,-0.1,x2,0);
Line2D(0,y1,0,y2); {vẽ trục y}
Line2D(+0.1,y2-0.2,0,y2); {vẽ hình mũi tên trên trục y}
Line2D(-0.1,y2-0.2,0,y2);

SetColor(lightgreen);
SetTextJustify(1,1);
for i := round(x1) + 1 to round(x2) - 1 do {vạch và ghi toạ độ trên trục x}
if i <> 0 then begin
str(i,x); {vạch i nguyên, chuyển số thành chữ}
outtextxy(tox(i),toy(-0.4),x); {để vẽ chữ lên màn hình}
Line2D(i,-0.1,i,0.1); {vẽ 1 đoạn thẳng làm vạch}
end;
for i := round(y1) + 1 to round(y2) - 1 do
if i <> 0 then begin
str(i,x);
outtextxy(tox(-0.4),toy(i),x);
Line2D(-0.1,i,0.1,i);
end;
end;
{Vẽ đường cong hàm số y = sinx, x = x1 -> x2}
procedure duongsin;
var x,y,a,b,dx : real;
i,n : integer;
begin
setcolor(yellow);
a := x1; b := x2; n := 100; dx := (b-a)/n;
x := a; y := sin(x);
moveto(tox(x),toy(y)); {dùng 2 hàm toX, toY để chuyển toạ độ thực thành toạ độ màn
hình}
for i := 1 to n do begin
x := x + dx; y := sin(x);
lineto(tox(x),toy(y));
end;
end;
{Vẽ đường cong tham số y = cos3t, y = sin5t, t= 0.. 2pi}
procedure thamso;
var t,x,y,a,b,dt : real;
i,n : integer;
begin
setcolor(lightred);
a := 0; b := 2*pi; n := 100; dt := (b-a)/n;

http://www.ebook.edu.vn 31
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
t := a; x := cos(3*t) ; y := sin(5*t);
moveto(tox(x),toy(y));
for i := 1 to n do begin
t := t + dt; x := cos(3*t) ; y := sin(5*t);
lineto(tox(x),toy(y));
end;
end;
{Vẽ đường cong toạ độ cực r = 3cos3p, p= 0 .. 2pi}
procedure tdcuc;
var r,p,x,y,a,b,dp : real;
i,n : integer;
begin
setcolor(13);
a := 0; b := 2*pi; n := 100; dp := (b-a)/n;
p := a; r := 3*cos(3*p);
x := r*cos(p) ; y := r*sin(p); {công thức đổi toạ độ cực sang toạ độ Đề các 2D}
moveto(tox(x),toy(y));
for i := 1 to n do begin
p := p + dp; r := 3*cos(3*p); x := r*cos(p) ; y := r*sin(p);
lineto(tox(x),toy(y));
end;
end;

BEGIN
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
khoitao_cuaso;
vetruc;
duongsin;
thamso;
tdcuc;
readkey;
END.

Ví dụ: MINH HOẠ CÁC PHÉP BIẾN ĐỔI 2D


uses crt,graph;
var gd, gm, xo, yo, w, h, n : integer;
x1,y1,x2,y2, xtl, ytl : real;
x,y : array[1..4] of real;

procedure khoitao_cuaso;
begin
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
xo := 20; yo := 40; w := 600; h := 400;
xtl := 30; ytl := 30;
x2 := w/xtl/2; x1 := -x2;
y2 := h/ytl/2; y1 := -y2;
end;

http://www.ebook.edu.vn 32
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
function tox(x : real): integer;
begin
tox := xo + round((x-x1)*xtl);
end;
function toy(y : real): integer;
begin
toy := yo + round((y2-y)*ytl);
end;

procedure Line2D(x1,y1,x2,y2: real);


begin
Line(tox(x1),toy(y1),tox(x2),toy(y2));
end;

procedure vetruc;
var i : integer;
x : string;
begin
Line2D(x1,0,x2,0);
Line2D(x2-0.2,+0.1,x2,0);
Line2D(x2-0.2,-0.1,x2,0);
Line2D(0,y1,0,y2);
Line2D(+0.1,y2-0.2,0,y2);
Line2D(-0.1,y2-0.2,0,y2);

SetColor(lightgreen);
SetTextJustify(1,1);
for i := round(x1) + 1 to round(x2) - 1 do
if i <> 0 then begin
str(i,x);
outtextxy(tox(i),toy(-0.4),x);
Line2D(i,-0.1,i,0.1);
end;
for i := round(y1) + 1 to round(y2) - 1 do
if i <> 0 then begin
str(i,x);
outtextxy(tox(-0.4),toy(i),x);
Line2D(-0.1,i,0.1,i);
end;
end;
(* Khởi tạo toạ độ các đỉnh hình chữ nhật*)
procedure khoitao_hcn;
begin
n := 4;
x[1] := 1; y[1] := 1;
x[2] := 1; y[2] := 3;
x[3] := 5; y[3] := 3;
x[4] := 5; y[4] := 1;

http://www.ebook.edu.vn 33
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
end;
(*Thủ tục vẽ hình chữ nhật*)
procedure VeHCN(c : integer);
begin
SetColor(c);
MoveTo(tox(x[1]), toy(y[1]));
LineTo(tox(x[2]), toy(y[2]));
LineTo(tox(x[3]), toy(y[3]));
LineTo(tox(x[4]), toy(y[4]));
LineTo(tox(x[1]), toy(y[1]));
end;
(* Tịnh tiến HCN theo vector (a,b) *)
procedure tinhtien(a,b : real);
var i : integer;
begin
for i := 1 to n do begin
x[i] := x[i] + a;
y[i] := y[i] + b;
end;
end;
(* Tịnh tiến HCN theo tỉ lệ (Sx,Sy) *)
procedure codan(Sx,Sy : real);
var i : integer;
begin
for i := 1 to n do begin
x[i] := Sx*x[i];
y[i] := Sy*y[i];
end;
end;
(* Tịnh tiến HCN theo góc a, đo bằng radian *)
procedure Quay(a : real);
var i : integer;
cosa,sina,tx,ty : real;
begin
cosa := cos(a); sina := sin(a);
for i := 1 to n do begin
tx := x[i] * cosa - y[i] * sina;
ty := x[i] * sina + y[i] * cosa;
x[i] := tx; y[i] := ty;
end;
end;
BEGIN
khoitao_cuaso;
khoitao_hcn;
vetruc;
VeHCN(14);
readkey;
tinhtien(-3,-2); {tịnh tiến HCN để tâm HCN là gốc toạ độ}

http://www.ebook.edu.vn 34
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
VeHCN(13);
readkey;
codan(1.2,2.4); {co dãn để HCN trở thành hình vuông :D}
VeHCN(12);
readkey;
quay(pi/4); {Quay HCN góc pi/4}
VeHCN(11);
readkey;
END.

Ví dụ: Vẽ các đường sin quay quanh gốc tọa độ


uses crt,graph;
var gd, gm, xo, yo, w, h : integer;
x1,y1,x2,y2, xtl, ytl : real;
(* CÁC THỦ TỤC HỆ ĐỒ HOẠ 2D *)
procedure khoitao_cuaso;
begin
xo := 20; yo := 40; w := 600; h := 400;
xtl := 30; ytl := 30;
x2 := w/xtl/2; x1 := -x2;
y2 := h/ytl/2; y1 := -y2;
end;
function tox(x : real): integer;
begin
tox := xo + round((x-x1)*xtl);
end;
function toy(y : real): integer;
begin
toy := yo + round((y2-y)*ytl);
end;
procedure Line2D(x1,y1,x2,y2: real);
begin
Line(tox(x1),toy(y1),tox(x2),toy(y2));
end;
procedure vetruc;
var i : integer;
x : string;
begin
SetColor(14);
Line2D(x1,0,x2,0);
Line2D(x2-0.2,+0.1,x2,0);
Line2D(x2-0.2,-0.1,x2,0);
Line2D(0,y1,0,y2);
Line2D(+0.1,y2-0.2,0,y2);
Line2D(-0.1,y2-0.2,0,y2);
SetColor(lightgreen);
SetTextJustify(1,1);
for i := round(x1) + 1 to round(x2) - 1 do

http://www.ebook.edu.vn 35
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
if i <> 0 then begin
str(i,x);
outtextxy(tox(i),toy(-0.4),x);
Line2D(i,-0.1,i,0.1);
end;
for i := round(y1) + 1 to round(y2) - 1 do
if i <> 0 then begin
str(i,x);
outtextxy(tox(-0.4),toy(i),x);
Line2D(-0.1,i,0.1,i);
end;
end;
{Vẽ đường sin y = sinx, x = -pi -> pi, quay 1 góc}
procedure quay(x,y,a:real; var tx,ty : real);
begin
tx := x * cos(a) - y * sin(a);
ty := x * sin(a) + y * cos(a);
end;
procedure duongsin(goc : real);
var x,y,a,b,dx,tx,ty : real;
i,n : integer;
begin
setcolor(15);
a := -2*pi; b := 2*pi; n := 50; dx := (b-a)/n;
x := a; y := sin(x); quay(x,y,goc,tx,ty);
moveto(tox(tx),toy(ty));
for i := 1 to n do begin
x := x + dx; y := sin(x); quay(x,y,goc,tx,ty);
lineto(tox(tx),toy(ty));
end;
end;
BEGIN
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
khoitao_cuaso;
vetruc;
duongsin(0);
duongsin(pi/4);
duongsin(pi/2);
duongsin(3*pi/4);
readkey;
END.

Ví dụ: Vẽ bầu trời sao

Uses crt,graph;
Var
gd,gm:integer;

http://www.ebook.edu.vn 36
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
s:array[1..100] of pointType;
n,i,j:integer;
procedure star(a,b:integer); {một ngôi sao lóe sáng}
var i:integer;
begin
for i:=2 to 10 do
begin
setcolor(random(GetMaxColor));
circle(a,b,i); delay(100);
setcolor(0); circle(a,b,i);
end;
end;

Begin
gd:=detect;
initgraph(gd,gm,'c:\tp\bgi');
setcolor(Yellow); n:=100;
Randomize;
for i:=1 to n do {n ngôi sao lần lượt hiện lên}
begin
delay(50);
s[i].x:=random(GetmaxX);
s[i].y:=random(GetmaxY);
putpixel(s[i].x,s[i].y,yellow);
end;
i:=0;j:=0;
{các ngôi sao lần lượt lóe sáng}
repeat
i:=i mod n +1; j:=j mod 10 +1;
if j <> 10 then putpixel(s[i].x,s[i].y,0)
else star(s[i].x,s[i].y);
delay(50);
s[i].x:=random(GetmaxX);
s[i].y:=random(GetmaxY);
putpixel(s[i].x,s[i].y,yellow);
until keypressed;
closeGraph;
End.

Ví dụ: Vẽ hộp chuyển động theo sự điều khiển của người dùng

{ Hộp vuông chuyển động theo phương ngang, chạm vào 2 biên và nảy ngược lại.
Nếu người dùng bấm phím mũi tên cùng chiều với chiều chuyển động của hộp thì hộp tăng
tốc độ, ngược lại sẽ giảm tốc độ.
Bấm phím mũi tên ÈÇ : quỹ đạo hộp sẽ được hạ xuống / nâng lên }

Uses crt,graph;

http://www.ebook.edu.vn 37
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
VAR
gd,gm:integer;
canh,buoc,direct,x,y,d:integer;
ch:char;
Procedure hop(x,y:integer);
begin
rectangle(x-canh,y-canh,x+canh,y+canh);delay(d);
rectangle(x-canh,y-canh,x+canh,y+canh);
end;

BEGIN
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
x:=100;y:=100; setwritemode(xorput);
d:=50; direct:=1; buoc:=2; canh:=10;
Repeat
repeat
hop(x,y);
if (0<x+direct*buoc) and (x+direct*buoc<GetmaxX) then
x:=x+direct*buoc
else direct:=direct*(-1);
until Keypressed;
ch:=readkey;
if ch=#0 then
begin
ch:=readkey;
case ch of
#72: if y>10 then y:=y-10;
#80: if y<getmaxY-10 then y:=y+10;
#75: if direct=1 then
begin if buoc>1 then dec(buoc); { hãm phanh }
end
else { direct=-1} inc(buoc); { tăng tốc }
#77: if direct=-1 then
begin if buoc>1 then dec(buoc); { hãm phanh }
end
else inc(buoc); { tăng tốc }
end;
end;
Until ch=#27;

closegraph;
END.

http://www.ebook.edu.vn 38
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chương III: Một số thuật toán đồ họa cơ bản

I. Vẽ đoạn thẳng

Xét đoạn thẳng y = m.x +b có hệ số góc 0<m<1, ta chọn điểm đầu và điểm cuối sao cho dx
=x2-x1>0. Làm sao để vẽ đoạn thẳng nối (x1,y1) (x2,y2) trong khi ta chỉ có thể ra lệnh cho
màn hình vẽ từng điểm ảnh (kiểư như PutPixel của TP)?

Làm sao vẽ
y2
đoạn thẳng nối
2 điểm nàyV
y1

x1 x2

Bản chất của quá trình này là sự rời rạc hóa và nguyên hóa một đối tượng thực (ở đây là
đoạn thẳng thực - đoạn thẳng toán học) trên màn hình sao cho cuối cùng ta có tập các Pixel
trông “giống” đối tượng nhất.
Bản chất của các thuật toán vẽ đoạn thẳng là đi tìm tập các pixel liền nhau sao cho
trông chúng “giống” với đoạn thẳng thực nhất
Thế nào là giống ?
- Liên tục (không đứt đoạn)
- Gần với đoạn thẳng thực (đoạn thẳng toán học) nhất
Hơn nữa, còn vấn đề tối ưu tốc độ, nghĩa là thuật toán phải tô các pixel trong thời gian
nhanh nhất
Bài toán: ta phải vẽ đoạn thẳng y = m.x +b có hệ số góc 0<m<1, dx>0 (các trường hợp
khác đều có thể quy về trường hợp này)
Đầu tiên ta nhận xét, với các đoạn thẳng dạng này, nếu (xi, yi) là điểm ảnh đã vẽ được ở
bước thứ i (điểm màu đen) thì
- chắc chắn xi+1 = xi +1
- yi+1 =yi hoặc yi+1 =yi +1
do đó điểm ảnh ở bước (i+1) tiếp theo chỉ có thể là 1 trong 2 trường hợp như hình vẽ. Vấn
đề quy về việc chọn điểm nào trong hai điểm đó.

(xi+1, yi+1)
2

(xi+1, yi)
yi 1

xi xi+1

http://www.ebook.edu.vn 39
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
1. Thuật toán DDA vẽ đoạn thẳng
Việc quyết định chọn yi+1 là yi hay yi+1 dựa vào phương trình của đoạn thẳng thực.

(xi+1, round(y))

(xi , yi) (xi+1, y)

Ta sẽ tính tọa độ của điểm y = m (xi +1) + b thuộc về đoạn thẳng thực, sau đó chọn điểm
nào gần với nó nhất trong 2 điểm, nghĩa là
yi+1 = round(y) = round(m.xi+1 +b)
Như vậy sẽ tốn 1 phép nhân và 1 phép cộng số thực. Để cải thiện tốc độ, người ta dùng cách
sau để khử phép nhân. Nhận xét rằng:
yi = m.xi + b
yi+1 = m.xi+1 +b ⇒ yi+1 = yi + m

Begin

Lưu đồ thuật toán


DDA m:=dy/dx ;
x:=x1; y:=y1;
putpixel(x,round(y));

No
x < x2 ? End

Yes
x:=x+1; y:=y+m;
PutPixel(x,round(y));

Ví dụ: Cho A(12,20) và B(22,27), ta có m=0.7

http://www.ebook.edu.vn 40
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

i xi yi y
0 12 20 20
1 13 21 20.7
2 14 21 21.4
3 15 22 22.1
4 16 23 22.8
5 17 24 23.5
6 18 24 24.2
7 19 25 24.9
8 20 26 25.6
9 21 26 26.3
10 22 27 27

Thuật toán DDA vẽ đoạn thẳng


{ Vẽ đoạn thẳng trong trường hợp 0<m<1, dx >0}
uses crt,graph;
var
gd,gm:integer;
i,x1,y1,x2,y2,x:integer;
y,m:real;
Begin
gd:=detect; initgraph(gd,gm,'');
Randomize;
Repeat {vẽ các đoạn thẳng ngẫu nhiên}
x1:=random(GetMaxX);
x2:=x1+random(GetMaxX-x1);
y1:=random(GetMaxY);
y2:=y1+random(x2-x1);
x:=x1; y:=y1;
m:=(y2-y1)/(x2-x1);
putpixel(x,round(y),white);
for i:=x1 to x2 do
begin
x:=x+1;
y:=y+m;
putpixel(x,round(y),white);
end;
delay(1000);
Until Keypressed;
closegraph;
End.

http://www.ebook.edu.vn 41
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

2. Thuật toán Bresenham vẽ đoạn thẳng

(xi+1,y)
yi+1 P
d2

y
d1
yi S

xi xi+1

Trong hình vẽ (xi+1,y) là điểm thuộc đoạn thẳng thực, ta có: y = m(xi+1) + b. Giả sử ở bước
i ta đã xác định được điểm (xi,yi).
Đặt
d1 = y – y1 ;
d2 = (yi +1) - y ;

Việc chọn điểm tiếp theo (xi+1, yi+1) là S hay P tùy thuộc vào việc d1 lớn hơn hay nhỏ hơn d2,
nói cách khác là phụ thuộc vào dấu của (d1 – d2)
• Nếu d1 – d2 <0, ta sẽ chọn S, tức là yi+1 = yi
• Trường hợp còn lại: d1 – d2 >0, ta sẽ chọn P, tức là yi+1 = yi+1
Đặt
pi = dx (d1 – d2).
Thay d1 = y – y1 ; d2 = (yi +1) – y vào ta có
pi = dx (2y - 2yi -1)
Thay y = mxi+b = dy(xi+1)/dx + b vào ta có
pi = 2dx [dy(xi+1)/dx +b] – 2yidx –dx
= 2xidy – 2yidx +C
với C = 2dy + (2b-1)dx là hằng số.
Ta nhận xét rằng, nếu tại bước thứ i ta xác định được dấu của pi thì sẽ xác định được điểm
cần tô ở bước i+1.
Làm sao để tính giá trị của pi ? ta dùng phương pháp “lũy tiến” như sau.
Ta có:
pi+1 –pi = (2xi+1dy – 2yi+1dx +C) - (2xidy – 2yidx +C) = 2dy -2dx(yi+1 – yi)
• Nếu pi<0 thì điểm được chọn là S, tức là yi+1 = yi ⇒ pi+1 = pi +2dy
• Nếu pi>0 thì điểm được chọn là P, tức là yi+1 = yi+1 ⇒ pi+1 = pi +2dy -2dx
Cuối cùng, giá trị p0 được tính từ điểm ảnh đầu tiên (x0, y0) theo công thức sau
p0 = 2x0dy – 2y0dx + c
Thay giá trị của c vào, chú ý rằng điểm đầu (x0, y0) cũng thuộc đoạn thẳng thực nên y0 =
mx0 + b = x0dy/dx + b, suy ra
p0 = 2dy -dx

tóm lại là:

http://www.ebook.edu.vn 42
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

p0 y1 p2 ...

y0 p1 y2 ...

Ví dụ:
Cho A(12,20) và B(22,27), ta có
dx = 22 – 12 = 10 ; dy = 27 – 20 = 7;
c1 = 2dy = 14 ; c2 = 2(dy-dx) = -6;
p0 = 2Dy – dx = 4

i xi yi pi
0 12 20 4
1 13 21 -2
2 14 21 12
3 15 22 6
4 16 23 0
5 17 24 -6
6 18 24 8
7 19 25 2
8 20 26 -4
9 21 26 10
10 22 27 4

http://www.ebook.edu.vn 43
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Lưu đồ thuật toán Begin


Bresenham

p:=2dy - dx ;
c1=2dy;
c2=2(dy-dx);
x:=x1; y:=y1 ;
putpixel(x,y);

No
x < x2 ? End

Yes
No
p<0?

Yes

p:=p+c1; p:=p + c2; y:=y+1;

x:=x+1;
PutPixel(x,y);

Thuật toán Bresenham vẽ đoạn thẳng

{ Vẽ đoạn thẳng trong trường hợp 0<m<1, dx >0}


uses crt,graph;
var
gd,gm:integer;
i,x1,y1,x2,y2,dx,dy,p,c1,c2,x,y:integer;
Begin
gd:=detect; initgraph(gd,gm,'');
Randomize;
Repeat
x1:=random(GetMaxX);
x2:=x1+random(GetMaxX-x1);
y1:=random(GetMaxY);
y2:=y1+random(x2-x1);
{vẽ đoạn thẳng (x1,y1) (x2,y2) }
http://www.ebook.edu.vn 44
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
dx:=x2-x1;
dy:=y2-y1;
p:=2*dy - dx;
c1:=2*dy;
c2:=2*(dy-dx);
x:=x1;
y:=y1;
putpixel(x,y,white);
for i:=x1 to x2 do
begin
if p<0 then p:=p+c1 else
begin
p:=p+c2; y:=y+1;
end;
x:=x+1;
putpixel(x,y,white);
end;
delay(1000);
Until Keypressed;
closegraph;
End.

3. Thuật toán MidPoint vẽ đoạn thẳng

yi+1 P

O: điểm giữa
yi S

xi xi+1
Thuật toán này thực chất là 1 cách diễn giải khác của thuật toán Bresenham. Ta lựa chọn
yi+1 là yi hay yi+1 bằng cách so sánh trung điểm của O của PS với đường thẳng thực
• Nếu O nằm phía dưới đường thẳng, ta chọn P
• Nếu O nằm phía trên, ta chọn S
Phương trình đường thẳng thực: Ax + By + C = 0
với A = y2 – y1; B = x1 – x2; C = x2y1 – x1y2 ;
Đặt F(x,y) = Ax + By + C, ta biết rằng
• F(x,y) <0 nếu điểm (x,y) nằm phía trên đường thẳng
• F(x,y) =0 nếu điểm (x,y) thuộc đường thẳng
• F(x,y) >0 nếu điểm (x,y) nằm phía dưới đường thẳng
vì vậy, vấn đề quy về việc xét dấu của pi = 2F(O) = 2F(xi +1,yi +1/2)
• Nếu pi <0 tức là O nằm phía trên đường thẳng ⇒ ta chọn S
http://www.ebook.edu.vn 45
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
• Nếu pi >0 tức là O nằm phía dưới đường thẳng ⇒ ta chọn P
Làm sao để tính pi ? tương tự như thuật toán Bresenham, ta cũng dùng phương pháp “lũy
tiến”, dùng giá trị ở bước trước pi để tính giá trị ở bước tiếp theo pi+1
Ta có: pi+1 – pi =2F(xi+1 +1,yi+1 +1/2) - 2F(xi +1,yi +1/2)
= 2[A(xi+1+1)+B(yi+1+1/2)+C] - 2[A(xi+1)+B(yi+1/2)+C]
= 2dy – 2dx(yi+1 – yi)
Như vậy
• Nếu pi <0 thì ta chọn yi+1 = yi , do đó pi+1 = pi +2dy
• Nếu pi >0 thì ta chọn yi+1 = yi+1 , do đó pi+1 = pi +2dy – 2dx
Cuối cùng, giá trị đầu p0 được tính như sau: nhận xét rằng điểm đầu (x0, y0) thuộc đoạn
thẳng thực tức là Ax0 + By0 +C = 0
p0 = 2F(x0+1,y0+1/2) = 2[A(x0+1)+B(y0+1/2)+C]
= 2(Ax0 + By0 +C) + 2A +B = 2A+B
= 2dy –dx

II Vẽ đường tròn

Thuật toán MidPoint

A
(-x, y) (x,y)
B
(-y, x) (y,x)

(-y, -x)
(y, -x)

(-x, -y) (x, -y)

Đầu tiên ta nhận xét rằng, do tính đối xứng của đường tròn nên ta chỉ cần vẽ được
cung AB là cung 1/8 đường tròn, sau đó lấy đối xứng qua các trục và các đường phân giác
ta sẽ có cả đường tròn. Chẳng hạn như ở hình vẽ trên nếu xác định được điểm (x,y), lấy đối
xứng qua đường phân giác của góc phần tư thứ nhất ta thu được điểm (y,x), lấy đối xứng
qua trục hoành ta thu được 2 điểm (y,-x) và (x,-y) ... Nếu ta chia thành 16,32 ... phần thì
việc xác định tọa độ 15,31... điểm đối xứng còn lại sẽ rất khó. Còn nếu chia thành 4 hay 2
phần thì số điểm lân cận cần phải loại trừ có thể nhiều hơn 2 điểm.

http://www.ebook.edu.vn 46
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

yi S Q(xi+1,y)

yi-1 P

M: điểm giữa

xi xi+1
Gọi R là bán kính đường tròn, ta xuất phát từ điểm A (0,R) để vẽ cung AB. Nhìn hình vẽ ta
thấy, nếu (xi, yi) là điểm ảnh đã vẽ được ở bước thứ i thì điểm ảnh (xi+1, yi+1) ở bước tiếp
theo chỉ có thể là S hoặc P, tức là
• xi+1 = xi + 1
• yi+1 ∈ {yi, yi-1}

Giống như thuật toán vẽ đoạn thẳng, ý tưởng chính để lựa chọn giữa S và P ở đây là căn cứ
vào vị trí tương đối của điểm giữa M của SP với đường tròn. Nếu M nằm bên trong đường
tròn như hình vẽ thì ta sẽ chọn S vì nó gần điểm thực Q hơn so với P. Ngược lại nếu M nằm
ngoài đường tròn thì P sẽ được chọn.

Đặt F(x,y) = x2 + y2 – R2 , các định lý toán học cho ta biết rằng


• F(x,y) <0 nếu điểm (x,y) nằm trong đường tròn
• F(x,y) =0 nếu điểm (x,y) nằm trên đường tròn
• F(x,y) >0 nếu điểm (x,y) nằm ngoài đường tròn

Đặt pi = F(M) = F(xi+1,yi – ½) ta có


• Nếu pi<0 tức là M nằm trong đường tròn, ta sẽ chọn S, tức là yi+1 = yi
• Nếu pi≥0 ta sẽ chọn P, tức là yi+1 = yi -1
Cách tính giá trị của pi cũng tương tự như ở thuật toán vẽ đoạn thẳng. Ta có:

pi+1 – pi = F[xi+1+1,yi+1 – ½] - F[(xi+1,yi – ½)]


= [(xi+1+1)2 +(yi+1 – ½)2 - R2] - [(xi+1)2 +(yi – ½)2 - R2]
= 2xi +3+(yi+12 – yi2) – (yi+1 - yi)
Do đó
• Nếu pi <0 ta chọn yi+1 = yi ⇒ pi+1 = pi + 2xi +3
• Nếu pi ≥0 ta chọn yi+1 = yi-1 ⇒ pi+1 = pi + 2xi -2yi +5
Cuối cùng ta tính giá trị đầu p0 ứng với điểm A(0,R)
p0=F(x0+1,y0-1/2) = F(0,R-1/2) = 5/4 -R

http://www.ebook.edu.vn 47
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Lưu đồ thuật toán Begin


MidPoint vẽ
đường tròn
p:=5/4 -R;
x:=0; y:=R ;
PutPixel8(x,y);

No
x<y? End

Yes
No
p<0?

Yes

p:=p+2x+3; p:=p+2(x-y); y:=y-1;

x:=x+1;
PutPixel(x,y);

Thuật toán MidPoint vẽ đường tròn


Uses crt,graph;
Var
gd,gm,x,y,R,p,mau:integer;

Procedure PutPixel8(x,y,c:integer);
Begin
putPixel(x,y,c); putPixel(y,x,c); putPixel(y,-x,c); putPixel(x,-y,c);
putPixel(-x,-y,c); putPixel(-y,-x,c); putPixel(-y,x,c); putPixel(-x,y,c);
End;

Begin
gd:=detect; initgraph(gd,gm,'');
SetViewPort(GetMaxX div 2, GetMaxY div 2, GetMaxX,GetMaxY,false);
Randomize;
R :=100 + random(200);
http://www.ebook.edu.vn 48
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
mau:=random(GetMaxColor); {Vẽ đường tròn MidPoint màu ngẫu nhiên }
x:=0; y:=R;
PutPixel8(x,y,mau);
p:=1-R;
while (x<y) do
begin
if p<0 then p:=p+2*x+3
else
begin
p:=p+2*(x-y)+5;
y:=y-1;
end;
x:=x+1;
PutPixel8(x,y,mau);
end;
readkey;
End.

VTại sao phải so sánh pi với 0 trong các thuật toán trên ? bản chất việc so sánh này là gì ?
VTrong thuật toán MidPoint, tại sao phải nhân F() với 2 khi gán cho pi trong công thức pi
= 2. F()

VHãy so sánh thuật toán vẽ đoạn thẳng DDA với 2 thuật toán còn lai về mặt tốc độ thực
hiện ? (Gợi ý: 2 thuật toán kia cải thiện đáng kể số phép tính cần thực hiện, vì sao? )

VVì sao nói thuật toán vẽ đoạn thẳng MidPoint chẳng qua là 1 cách diễn giải khác của
thuật toán Bresenham ?

VTrong thuật toán vẽ đường tròn MidPoint, vì sao không chia đường tròn thành nhiều hơn
hoặc ít hơn 8 phần ?

VTrong chương trình minh họa thuật toán vẽ đường tròn MidPoint, tại sao không để như
lý thuyết là: p0 := 5/4 –R mà sửa thành p0:= 1- R ?

III Cắt xén (Clipping)

1. Thuật toán Cohen-Sutherland

Bài toán: giả thiết rằng cửa sổ hiển thị là một hình chữ nhật với các cạnh song song với các
trục tọa độ như hình vẽ. Cho một đoạn thẳng bất kỳ, hãy xác định phần nào của nó nằm
trong cửa sổ (tức là được hiển thị), phần nào nằm ngoài (bị che khuất).

http://www.ebook.edu.vn 49
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

1001 1000 1010


D
C E
ymax
B
0001
F
J 0000 L
A K’ 0010
J’ K
ymin I’

0101 0100 0110


I

xmin xmax

Cách làm: đầu tiên ta nhận xét rằng một điểm P(x,y) nằm trong cửa sổ (được nhìn thấy) khi
và chỉ khi thỏa mãn đồng thời 2 điều kiện
xmax ≥ x ≥ xmin
ymax ≥ y ≥ ymin
Ngược lại, nếu một trong 2 điều kiện bị vi phạm thì P nằm ngoài cửa sổ và sẽ không được
hiển thị.
Các đoạn thẳng chỉ có thể thuộc một trong những trường hợp sau:
• Hoàn toàn nằm trong cửa sổ, ví dụ như AB, khi đó cả 2 đầu mút đều nằm bên trong
cửa sổ
• Hoàn toàn nằm ngoài cửa sổ (bị che toàn phần), ví dụ như CD, EF
• Chỉ một phần nằm trong cửa sổ và được hiển thị, ví dụ như KL và IJ

Đầu tiên, thuật toán Cohen – Sutherland dùng 4 đường thẳng chứa cạnh cửa sổ
chia mặt phẳng thành 9 phần. Mỗi điểm A(x,y) thuộc mặt phẳng sẽ được gán mã 4 bit abcd
theo cách sau:
• a=1 ⇔ y > ymax : A nằm phía trên cửa sổ
• b=1 ⇔ y < ymin : A nằm phía dưới cửa sổ
• c=1 ⇔ x > xmax : A nằm phía phải cửa sổ
• d=1 ⇔ x < xmin : A nằm phía trái cửa sổ
Khi đó, ta nhận xét rằng:
• đoạn thẳng sẽ hoàn toàn nằm trong cửa sổ nếu cả 2 đầu mút đều bằng 0000
• đoạn thẳng sẽ hoàn toàn nằm ngoài cửa sổ nếu kết quả phép AND của 2 đầu mút
khác 0000
Thực vậy, nhận xét đầu là hiển nhiên. Để minh họa cho nhận xét 2, xét đoạn thẳng EF:
E = 1010, F = 0010 ⇒ (E) AND (F) = (1010) and (0010) = 0010 ≠ 0
bit thứ 3 của cả 2 đầu mút E và F đều bằng 1, chứng tỏ chúng đều nằm bên phải cửa sổ, do
đó cả đoạn thẳng dĩ nhiên cũng nằm bên phải cửa sổ và sẽ không được hiển thị.
Vấn đề còn lại là, nếu kết quả phép AND hai đầu mút bằng 0000, khi đó thuật toán sẽ
tìm giao của đoạn thẳng với các biên của cửa sổ và xét từng phần của nó. Ta ký hiệu 4
đường thẳng chứa cạnh cửa sổ là:

http://www.ebook.edu.vn 50
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
• đường 1: y = ymax
• đường 2: y = ymin
• đường 3: x = xmax
• đường 4: x = xmin
Khi đó nhìn vào mã của 2 đầu mút ta sẽ biết ngay đoạn thẳng đó cắt cạnh nào của cửa sổ. Ví
dụ:

4 3

ymax 1
0001
J L 0010
K’
J’ K
ymin I’ 2

0100
I

xmin xmax

Xét đoạn IJ
• Mã của I = 0100, bít thứ 2 =1 nên chắc chắn nó sẽ cắt đường 2
• Mã của J = 0001, bít thứ 4 =1 nên chắc chắn nó sẽ cắt đường 4
Xét đoạn KL
• Mã của L = 0100, bít thứ 3 =1 nên chắc chắn nó sẽ cắt đường 3

Việc xác định tọa độ giao điểm là rất đơn giản vì ta đã biết rõ 2 đầu mút. Sau khi chia đoạn
thẳng thành các đoạn, ta lặp lại thuật toán với mỗi đoạn chia cho đến khi kết thúc. Ví dụ ta
xét đoạn IJ
• Bước 1: kết quả phép and bằng 0 nhưng 2 đầu mút khác 0: tìm giao điểm với biên I’
• Bước 2: loại đoạn II’
• Bước 3: xét đoạn JI’ : tìm giao điểm J’
• Bước 4: loại đoạn JJ’. Kết thúc với đoạn I’J’ được hiển thị

2. Thuật toán Sutherland - Hodgman

Bài toán: ta cần cắt 1 đa giác bất kỳ Y vào trong cửa sổ là một đa giác lồi X.

Cách làm: Ta sẽ duyệt lần lượt các cạnh của X, với mỗi cạnh đó ta lại xét lần lượt cạnh của
Y. Kết quả sau khi xén với cạnh thứ i (của cửa sổ X) sẽ được dùng để xén với cạnh tiếp theo
i+1 của X. Quy tắc là:

http://www.ebook.edu.vn 51
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
• nếu cạnh đang xét của Y đi từ trong cửa sổ ra ngoài (Pi-1 ở trong, Pi ở ngoài) thì chỉ
giữ lại giao điểm I của Pi-1 Pi với cạnh đang xét của X.
• nếu cạnh đang xét đi từ ngoài vào trong (tức là Pi-1 ở ngoài, Pi ở trong): giữ lại giao
điểm I và Pi
• trường hợp cạnh ở ngoài hoàn toàn: loại bỏ
• trường hợp cạnh ở trong hoàn toàn: giữ lại Pi .

V
C
A
P
Q
B R
H
G
J
D
E
I
U T
M
K
F

Ví dụ
Đầu tiên ta xét cạnh UV của cửa sổ cắt là tam giác UVT.

Cạnh đang xét (theo chiều vecto) Hướng đi Quyết định giữ lại
AB (xét với UV) Từ ngoài vào trong P,B
BC (xét với VT) Trong ra ngoài Q
CD Ngoài vào trong R,D
DE Hoàn toàn nằm trong E
EK (xét với TU) Trong ra ngoài M
KF Hoàn toàn nằm ngoài Loại hết
FG Ngoài vào trong I,G
GH (xét với UV) Trong ra ngoài J
HA Hoàn toàn nằm ngoài Loại hết

Ta thu được đa giác (theo thứ tự): P,B,Q,R,D,E,M,I,G,J như hình vẽ


Đoạn mã giả (pseudocode) sau minh họa cho thuật toán trên.

t:=1
for i:=1 to n do {Đa giác cửa sổ X có n cạnh}
for j:=1 to m do {Đa giác bị cắt Y có m cạnh }
k:=j+1; {Xét cạnh XjXj+1 của đa giác cửa sổ X}
if k>n then k:=1 ;
if (Xj ở trong) then
http://www.ebook.edu.vn 52
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
begin
if (Xk ở trong) then Yt := Yk
else Yt := giao điểm của XjXk với cạnh i của X
t:=t+1;
end
else
if (Xk ở trong ) then
begin
Yt := giao điểm;
t:=t+1;
Yt := Xk ;
t:=t+1;
end;

Vấn đề: cho tọa độ 1 điểm, làm sao biết điểm đó ở trong/ngoài đa giác lồi X ?

Bổ đề: nếu điểm đó nằm bên phải 1 cạnh nào đó của đa giác lồi X theo chiều dương thì nó
nằm ngoài X. Nếu nó nằm bên trái tất cả các cạnh thì nó nằm bên trong X

B(x2,y2)

P(x,y)

chiều dương
bên phải

bên trái A(x1,y1)

Bổ đề: cho vector AB và điểm P(x,y), P nằm bên trái vector AB (như hình vẽ) nếu và chỉ
nếu (x2 – x1)(y – y1) – (y2 – y1)(x – x1) >0
Ta công nhận, không chứng minh bổ đề toán này.

Vấn đề: cho tọa độ tập đỉnh của đa giác lồi X dưới dạng 1 danh sách có thứ tự (nghĩa là nếu
biết 1 đỉnh thì ta luôn biết 2 đỉnh kề của nó), làm sao xếp chúng lại “theo chiều dương” ?

Cách làm: Chọn đỉnh có hoành độ nhỏ nhất, ký hiệu là A như hình vẽ. Gọi 2 đỉnh kề nó là
B,C trong đó xB < xC. Thứ tự theo chiều dương sẽ là BAC. Sau đó ta chỉ việc đi tới đỉnh tiếp
theo C ...
Thật vậy, ta có thể thấy rõ khi nhìn hình vẽ. Chỉ có 3 trường hợp:
• B,C nằm ở 2 phía của đường thẳng x = xA
• B,C cùng nằm bên phải đường thẳng đó
• B,C cùng nằm bên trái

http://www.ebook.edu.vn 53
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

B C C
C B
B

A A A

2. Clipping một đoạn thẳng vào đường tròn

A
A
D

d d
B C
O O
A

B
B
(a) (b) (c)

Gọi d là khoảng cách từ tâm O tới đoạn thẳng AB.


• Nếu d > bán kính r ⇒ clip(AB) = ∅
• Nếu d = bán kính r ⇒ clip(AB) = {điểm tiếp xúc}
• Nếu d < bán kính r, ta chia thành 3 trường hợp
o Cả A,B đều nằm trong đường tròn: clip(AB) = AB
o Một trong hai điểm (giả sử là A) nằm ngoài đường tròn. Gọi C là giao của AB
với đường tròn ta có clip(AB) = BC
o Cả 2 cùng nằm ngoài đường tròn, xét dấu:
ƒ Nếu (xA-xC) (xB-xC) <0 thì clip(AB)=CD (trường hợp (c))
ƒ Nếu (xA-xC) (xB-xC) >0 thì clip(AB)=∅ (trường hợp (b))

IV. Tô màu vùng khép kín

Cho một vùng khép kín được giới hạn bởi một đường biên đồng màu. Vấn đề đặt ra là tô
màu cho miền trong của vùng đó. Có 2 phương pháp chính: tô theo dòng quét (scan line fill)
và tô dựa theo đường biên (boundary fill).

1. Thuật toán tô màu theo đường biên (Boundary algorithm)

Cách tô này yêu cầu phải biết trước tọa độ một điểm (điểm “gieo”) nằm bên trong
vùng cần tô. Bắt đầu từ điểm đó ta sẽ tô “loang” dần ra các vùng xung quanh bằng việc đọc
màu của các điểm lân cận để kiểm tra xem chúng đã được tô màu hay chưa. Nếu đã được tô,
http://www.ebook.edu.vn 54
Đồ họa máy tính - Khoa CNTT - ĐHSPHN
hoặc màu của điểm lân cận là màu của biên thì dừng lại và xét điểm khác, nếu không thì tô
điểm lân cận đó.
Có vài phương pháp khác nhau để xác định lân cận như: loại 4 điểm, loại 8 điểm

Lân cận 4 điểm Lân cận 8 điểm

Procedure BFill ( x,y,c,B:integer)


{(x,y) điểm đang xét, c: màu tô, B: màu đường biên }
Var
t: integer;
Begin
t:=GetPixel(x,y);
if (t <>B) and (t<>c) then
{
putpixel(x,y,c);
BFill(x-1,y,c,B);
BFill(x+1,y,c,B);
BFill(x,y-1,c,B);
BFill(x,y+1,c,B);
}
Cách làm như trên có nhược điểm là khi gọi đệ quy cho 4 điểm lân cận không xét tới việc
chúng đã được kiểm tra ở các bước trước hay chưa. Cần có cải tiến để không xét lại những
điểm đã được kiểm tra rồi.

2. Thuật toán tô màu dựa theo dòng quét (Scan-line algorithm)

Giả sử dùng cần tô là một đa giác N đỉnh {Pi =(xi,yi)} i=1..N


Ta sử dụng 1 dòng quét song song với trục Ox đi từ đỉnh trên cùng (Ymax) đến đỉnh
dưới cùng (Ymin) của vùng cần tô. Với mỗi giá trị y = yi, dòng quét cắt các đường biên của
vùng cần tô tạo thành các đoạn thẳng. Ta tô màu các điểm nằm giữa hai đầu mút của các
đoạn thẳng đó.

http://www.ebook.edu.vn 55
Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Ymax

Ymin

Các bước:
- Xác định Ymax, Ymin của đa giác cần tô
- Với mỗi dòng quét y = yi (Ymin ≤ yi ≤ Ymax), xác định hoành độ giao điểm với các
cạnh của đa giác
- Sắp xếp chúng theo thứ tự tăng dần thành các cặp (x0, x1) ...
- Tô các đoạn (x0, x1), (x2, x3), (x4, x5) ...
Tuy nhiên, có một ngoại lệ là khi dòng quét đi qua đỉnh P của đa giác. Khi đó ta phải chia
thành 2 trường hợp:
- Nếu 2 cạnh kề của P có hướng ngược nhau, một cạnh đi lên một cạnh đi xuống thì
trong danh sách giao điểm ta sẽ tính là 2 giao điểm có tọa độ trùng nhau ở đỉnh P.
Nghĩa là xi = xi+1 = xP
- Nếu 2 cạnh kề của P cùng hướng nhau, cả hai cùng đi lên hoặc đi xuống thì P chỉ
được tính là 1 giao điểm.

1 4
2,3

2 3
1

http://www.ebook.edu.vn 56

You might also like