Phần hiển thị của hình Phần này chúng ta giải quyết bài toán sau: Giả sử đối tượng quan sát nằm trong vùng nhìn thấy, khi đó nó có ảnh trên mặt phẳng chiếu Π.. Nếu bây giờ chúng ta thu
Trang 1Chương 4
Kỹ thuật xử lý hình khuất
$12 Phần hiển thị của hình
Phần này chúng ta giải quyết bài toán sau:
Giả sử đối tượng quan sát nằm trong vùng nhìn thấy, khi đó nó có ảnh trên mặt phẳng chiếu Π Nếu bây giờ chúng ta thu nhỏ mặt phẳng chiếu, hãy xác định phần hình ảnh của đối tượng có trong mặt phẳng chiếu, chúng ta chú ý rằng vấn đề này rất phù hợp với yêu cầu đặt ra khi mô tả đối tượng trên máy tính Nếu chúng ta coi màn hình là mặt phẳng chiếu hay một vòng hình chữ nhật (cửa sổ) trên màn hình là mặt phẳng chiếu (Trong Pascal, C ta gọi vùng chiếu đó là ViewPort)
Không giảm tổng quát ta giả sử cửa sổ trên mặt phẳng chiếu có kích thước [Xmin,
Xmax] x [Ymin,Ymax]
1 Thuật toán Cohen Sutherland
Thuật toán Cohen Sutherland giải quyết bài toán làm thế nào để xác định phần đoạn thẳng có trong mặt phẳng chiếu Nói một cách khác làm thế nào để xác định phần
đường thẳng cho trước có trong Viewport
Theo Cohen Sutherland một cửa sổ sẽ chia màn hình thành 9 phần mỗi phần ứng với một mã số gồm 4 bit
Mμn hình cửa sổ
Đường thẳng
X O
Y Ymax Ymin
Trang 2Một điểm P bất kỳ thuộc mặt phẳng chiếu sẽ ứng với một mã gọi là Kod(P)
Kod(P)=b4b3b2b1 Trong đó các bi đ−ợc xác định nh− sau:
( ) 1
b = 1
b = 1
b = 1
b = 1
1
2
3
4
nếu P nằm ở bê n trái của cửa sổ nếu P nằm ở bê n phải của cửa sổ nếu P nằm ở phần bê n d – ới của cửa sổ nếu P nằm ở phần bê n trê n của cửa sổ
⎧
⎨
⎪
⎪
⎩
⎪
⎪
Nếu không thoả mãn điều kiện trên thì bi =0, i=1 4,
Một điểm P(x,y) bất kỳ Kod(P)đ−ợc xác định theo (1) nh− sau:
b
1=1 nếu x<xmin b
2=1 nếu x>xmax b
3=1 nếu y>ymax b
4=1 nếu y<ymin Với cách tính này ta suy ra:
b1 lμ bit dấu của x-xmin
b2 lμ bit dấu của xmax-x
b3 lμ bit dấu của ymax-y
b4 lμ bit dấu của y-ymin (Chú ý trong máy tính bit dấu bằng 1 thì có dấu -)
Chúng ta quy −ớc nếu điểm P∈biên của cửa sổ thì Kod(P)=0
Với cách xác định mã ở trên của điểm P ta suy ra P∈ cửa sổ viewport khi
Kod(P)=0000
Do đó
i đoạn thẳng P1P2 thuộc cửa sổ khi
Kod(P1)=Kod(P2)=0000
ii đoạn thẳng sẽ nằm hoàn toàn bên ngoài cửa sổ khi
1001 1000 1010
0001 Viewport 0010
0000
0101 0100 0110
Trang 3( Kod(P1) And Kod(P2) )≠0000 iii còn lại đoạn thẳng sẽ nằm cả trong lẫn ngoài cửa sổ nghĩa là khi
((Kod(P1) And Kod(P2) ) = 0000) And (( Kod(P1) ≠0000) Or (Kod(P2) ≠0000)) Xác định điểm giao của đoạn thẳng với các cạnh của cửa sổ sau đó vứt bỏ phần không thuộc cửa sổ thuật toán có thể minh hoạ bằng hình sau:
Có thể mô tả thuật toán Cohen-Sutherland như sau:
Giả sử điểm P1 có toạ độ là (x1,y1) và P2 có toạ độ là (x2,y2)
và cửa sổ nhìn có toạ độ là (xmin, ymin)-(xmax,ymax)
1 Tính Kod(P1) và Kod(P2)
2 Nếu Kod(P1)=Kod(P2)=0000 thì P1P2 nằm trong nhẩy đến 5
3 Nếu (Kod(P1) And Kod(P2))<>0000 thì P1P2 nằm ngoài nhẩy đến 6
4 Ngược lại không thoả mãn 2 điều kiện trên thực hiện
- Nếu Kod(P1)=0000 thì ta hoán vị P1 với P2 để Kod(P1)<>0000 và lấy b4b3b2b1= Kod(P1)
- Nếu b1=1 thì y1=y1+(xmin-x1)*(y2-y1)/(x2-x1); x1=xmin
- Nếu b2=1 thì y1=y1+(xmax-x1)*(y2-y1)/(x2-x1); x1=xmax
- Nếu b3=1 thì x1=x1+(ymin-y1)*(x2-x1)/(y2-y1); y1=ymin
- Nếu b4=1 thì x1=x1+(ymax-y1)*(x2-x1)/(y2-y1); y1=ymax
- Quay lại bước 1
5 Vẽ đoạn thẳng P1P2
6 Kết thúc
ở trên chúng ta có thực hiện phép chia cho (x2-x1) và phép chia cho (y2-y1) cho nên trước tiên chúng ta phải xét các trường hợp x2=x1 và trường hợp y2=y1, hai trường hợp này đơn giản tự làm
Chương trình minh họa :
Program Cohen_Sutherland;
uses crt,graph;
type
code=array[1 4] of Byte;
P2 P'2 Bỏ
P4 P"1
P'3 P'1
P3 P1
Trang 4var
a1,b1,a2,b2 : Real;
n,i, xmin,ymin,xmax,ymax,gd,gm:integer;
b: code;
(****************************************)
Procedure Special_Line(x1,y1,x2,y2: Real);
Var
tg: Real;
Begin
If (x1=x2) And (x1>xmin) And (x1<xmax) Then
Begin
If y1>y2 Then
Begin
tg:=y1; y1:=y2; y2:=tg;
End;
If (y1<ymax) And (y2>ymin) Then
Begin
If y1<ymin Then y1:=ymin;
If y2>ymax Then y2:=ymax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
If (y1=y2) And (y1>ymin) And (y1<ymax) Then
Begin
If x1>x2 Then
Begin
tg:=x1; x1:=x2; x2:=tg;
End;
If (x1<xmax) And (x2>xmin) Then
Begin
If x1<xmin Then x1:=xmin;
If x2>xmax Then x2:=xmax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
End;
(*****************************)
Procedure Kod(x,y:real;var b:code );
Begin
For i:=1 To 4 Do b[i]:=0;
if(x < xmin) then b[1]:=1;
if(x > xmax) then b[2]:=1;
if(y < ymin) then b[3]:=1;
if(y > ymax) then b[4]:=1;
End;
Trang 5(****************************************)
Procedure Cohen_Sutherland_Clipping(x1,y1,x2,y2:Real);
var
c1,c2: code;
chon,tong1,tong2,mu2: Byte;
tgx,tgy : Real;
Begin
Repeat
Kod(x1,y1,c1); Kod(x2,y2,c2);
tong1:=0; tong2:=0; mu2:=1;
For i:=1 To 4 Do
Begin
tong1:=tong1+c1[i]*mu2;
tong2:=tong2+c2[i]*mu2;
mu2:=mu2*2;
End;
If tong1+tong2=0 Then
Begin
chon:=1;
line(Round(x1),Round(y1),Round(x2),Round(y2));
End
Else If (tong1 And tong2)<>0 then
Begin
chon:=2;
End
Else
Begin
chon:=3;
If tong1=0 then
Begin
tgx:=x1; x1:=x2; x2:=tgx;
tgy:=y1; y1:=y2; y2:=tgy;
End;
Kod(x1,y1,b);
if b[1]=1 then
Begin
y1:=y1+(xmin-x1)*(y2-y1)/(x2-x1); x1:=xmin
End;
if b[2]=1 then
Begin
y1:=y1+(xmax-x1)*(y2-y1)/(x2-x1); x1:=xmax
End;
if b[3]=1 then
Begin
x1:=x1+(ymin-y1)*(x2-x1)/(y2-y1); y1:=ymin
Trang 6End;
if b[4]=1 then
Begin
x1:=x1+(ymax-y1)*(x2-x1)/(y2-y1); y1:=ymax
End;
End;
Until (chon=1) Or (chon=2);
End;
(****************************************)
Begin
clrscr;
write('nhap toa do cua so xmin,ymin: ');
readln(xmin,ymin);
write('nhap toa do cua so xmax,ymax: ');
readln(xmax,ymax);
write('Nhap (a1,b1): '); readln(a1,b1);
write('Nhap (a2,b2): '); readln(a2,b2);
gd:=detect;
initgraph(gd,gm,'c:\tp\bgi');
setbkcolor(Black);
setcolor(red);
rectangle(xmin,ymin,xmax,ymax);
settextjustify(1,1);
outtextxy(320,450,'HIEN THI MOT DOAN THANG TRONG MOT CUA SO CHO TRUOC');
outtextxy(320,470,'THEO THUAT TOAN COHEN-SUTHERLAND');
setcolor(WHITE);
setlinestyle(1,0,0);
line(Round(a1),Round(b1),Round(a2),Round(b2));
setlinestyle(0,0,0);
If (a1<>a2)And(b1<>b2) Then Cohen_Sutherland_Clipping(a1,b1,a2,b2)
Else Special_Line(a1,b1,a2,b2);
readln;
closegraph;
End
2 Thuật toán Liang-Barsky
Thuật toán xác định phần đường thẳng của Cohen Shutherland tương đối đơn giản và thuận tiện, tuy nhiên nó có nhược điểm khi người lặp lại quá trình xác định giao
điểm của đoạn thẳng với cửa sổ phải tiến hành nhiều phép nhân, chia điều này sẽ dẫn đến hậu quả là thời gian xử lý chậm, gặp nhiều sai số Hai nhà toán học Liang
và Barsky đã đưa ra một thuật toán khác để khắc phục nhược điểm trên Giả sử đoạn thẳng cho dưới dạng tham số đi qua 2 điểm P1(x1,y1), P2(x2,y2) có dạng:
x = x + tdx
y = y + tdy
1 1
⎧
⎨
Trang 7với dx=x
2-x
1; dy=y
2-y
1 t∈[0,1]
Giả sử cửa sổ giới hạn bởi hai điểm ở góc trên bên trái và góc dưới bên phải
(xmin,ymin) , (xmax,ymax) khi đó đoạn thẳng thuộc vào cửa sổ khi và chỉ khi
x x + tdx x
y y + tdy y
≤
≤
≤
≤
⎧
⎨
⎩
⇔ x - x tdx x - x
y - y tdy y - y
⎧
⎨
⎩
⇔ t.pk≤qk , k=1,2,3,4 (2) Với p
1=-dx q
1=x
1-xmin p
2=xmax-x1
p3=-dy q3=y1-ymin
p4=dy q4=ymax-y1
Từ (2) ta suy ra:
1 Nếu có k (bằng 1 hoặc 3) để p
k=0 thì đoạn thẳng song song với một cạnh nào đó của cửa sổ
2 Nếu với ∀k mà pk≠0 thì ta xác định t1 và t2
t1=Max{0,Max(qk/pk)} với các pk<0
t2=Max{(1,Min(qk/pk)} với các pk>0
khi đó xác định được đoạn thẳng (xw1,yw1)-(xw2,yw2) nằm trong cửa sổ
xw1=x1+t1*dx; yw1=y1+t1*dy
xw2=x1+t2*dx; yw2=y1+t2*dy
Ta có thuật toán Liang Barsky
1 đặt t1=0; t2=1;
2 Tính pk và qk theo công thức trên với k=1,2,3,4
3 Nếu có pk=0 thì đoạn thẳng song song với 1 trong 2 cạnh của cửa sổ
4 Nếu pk<>0 (với k=1,2,3,4) thì
- Cho k chạy từ 1 đến 4
- đặt t=qk/pk
- nếu pk<0 thì đặt t1=max(t1,t)
- nếu pk>0 thì đặt t2=min(t2,t)
5 Nếu t1<=t2 thì toạ độ giao của đoạn thẳng với cửa sổ là
+ xw1=x1+t1*dx ; yw1=y1+t1*dy
+ xw2=x1+t2*dx ; yw2=y1+t2*dy
+ vẽ đoạn thẳng (xw1,yw1)-(xw2,yw2)
6 Nếu t1>t2 thì P1P2 nằm ngoài cửa sổ và kết thúc
Chương trình minh họa :
Program Liang_Barsky;
Uses Crt,Graph;
Trang 8Var
gd,gm,k : integer;
xmin,xmax,ymin,ymax : integer;
a1,b1,a2,b2,dx,dy : Real;
p,q : Array[1 4] Of Real;
(*****************************)
Procedure Special_Line(x1,y1,x2,y2: Real);
Var
tg: Real;
Begin
If (x1=x2) And (x1>xmin) And (x1<xmax) Then
Begin
If y1>y2 Then
Begin
tg:=y1; y1:=y2; y2:=tg;
End;
If (y1<ymax) And (y2>ymin) Then
Begin
If y1<ymin Then y1:=ymin;
If y2>ymax Then y2:=ymax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
If (y1=y2) And (y1>ymin) And (y1<ymax) Then
Begin
If x1>x2 Then
Begin
tg:=x1; x1:=x2; x2:=tg;
End;
If (x1<xmax) And (x2>xmin) Then
Begin
If x1<xmin Then x1:=xmin;
If x2>xmax Then x2:=xmax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
End;
(*****************************)
Procedure Liang_Barsky_Clipping(x1,y1,x2,y2: Real);
Var
xw1,yw1,xw2,yw2,t,t1,t2: Real;
Begin
t1:=0; t2:=1;
dx:=x2-x1; dy:=y2-y1;
p[1]:=-dx; p[2]:=dx; p[3]:=-dy; p[4]:=dy;
Trang 9q[1]:=x1-xmin; q[2]:=xmax-x1; q[3]:=y1-ymin; q[4]:=ymax-y1;
For k:=1 To 4 Do
Begin
t:=q[k]/p[k];
If p[k]<0 then If t1<t Then t1:=t;
If p[k]>0 then If t2>t then t2:=t;
End;
If t1<=t2 then
Begin
xw1:=x1+t1*dx; yw1:=y1+t1*dy;
xw2:=x1+t2*dx; yw2:=y1+t2*dy;
Line(Round(xw1),Round(yw1),Round(xw2),Round(yw2));
End;
End;
(*****************************)
Begin
Clrscr;
write('Nhap (xmin,ymin): '); readln(xmin,ymin);
write('Nhap (xmax,ymax): '); readln(xmax,ymax);
write('Nhap (a1,b1): '); readln(a1,b1);
write('Nhap (a2,b2): '); readln(a2,b2);
gd:=detect;
Initgraph(gd,gm,'C:\tp\bgi');
setcolor(White);
setlinestyle(1,0,0);
Line(Round(a1),Round(b1),Round(a2),Round(b2));
setlinestyle(0,0,0);
If (a1<>a2) And (b1<>b2) Then Liang_Barsky_Clipping(a1,b1,a2,b2)
Else Special_Line(a1,b1,a2,b2);
settextjustify(1,1);
outtextxy(320,450,'HIEN THI MOT DOAN THANG TRONG MOT CUA SO CHO TRUOC');
outtextxy(320,470,'THEO THUAT TOAN LIANG_BARSKY');
rectangle(xmin,ymin,xmax,ymax);
Readln;
Closegraph;
End
$13 Vùng nhìn thấy
Trong khi quan sát các vật thể trong không gian chúng ta gặp hai tình huống sau:
1 Từ vị trí quan sát chúng ta có thể nhìn thấy một phần hay không nhìn thấy vật thể
Điều này phụ thuộc vào vị trí và góc nhìn của người quan sát đối với vật thể