การแปลงในสามมิติ

Download Report

Transcript การแปลงในสามมิติ

418382 สภาพแวดล้อมการทางานคอมพิวเตอร์กราฟิ กส์
การบรรยายครั้งที่ 3
ประมุข ขันเงิน
[email protected]
การแปลงในสามมิติ
ในปริ ภูมิสามมิติ
• พิกดั ในสามมิติแทนด้ วยลาดับ (x,y,z)
• หรื อด้ วย (x,y,z,w) ถ้ าอยูใ่ นรูป homogeneous
coordinate
• homogeneous coordinate (x,y,z,w) หมายถึงพิกดั
(x/w, y/w, z/w) ในปริภมู ิสามมิติ
ในปริ ภูมิสามมิติ (ต่อ)
• พิกดั ในสามมิติสามารถเขียนได้ อีกแบบหนึง่ ในรูป matrix
x
 y
 
z
 
1 
• มีความหมายเหมือนกับ homogeneous coordinate
(x,y,z,1)
การแปลงในปริ ภูมิสามมิติ
• การแปลงแอฟไฟน์สามชนิดที่เรี ยนผ่านมา
– การเลื่อนแกนขนาน (translation)
– การย่อขยาย (scaling)
– การหมุน (rotation)
สามารถแทนได้ ด้วย matrix 4 คูณ 4
การเลื่อนแกนขนาน
• สัญลักษณ์ Ta,b,c
• ส่งพิกดั (x,y,z) ไปยังพิกดั (x+a, y+b, z+c)
• มี matrix เป็ น
1
0

0

0
0
1
0
0
0
0
1
0
a

b
c

1
การย่อขยายขนาด
• สัญลักษณ์ Sa ,b,c
• ส่งพิกดั (x,y,z) ไปยังพิกดั (ax, by, cz)
• นี่เป็ นการย่อขยายรอบพิกดั (0,0,0) เนื่องจากพิกดั (0,0,0) ไม่
เปลี่ยนแปลง
• มี matrix เป็ น a 0 0 0
 0 b 0 0


 0 0 c 0


0 0 0 1
การหมุน
• เวลาหมุนจะต้ องบอกสองอย่าง
– แกนที่จะใช้ หมุน
– มุมที่จะใช้ หมุน
• เวลาระบุแกนเราจะระบุด้วยเวกเตอร์ (a,b,c)
• แกนคือเส้ นตรงที่เกิดจากจุดทังหมดที
้
่อยูใ่ นรูป (at, bt, ct) เมื่อ t เป็ น
จานวนจริ งใดๆ
• แกนจะผ่านจุด (0,0,0) เสมอ
• เวลาทาการหมุน จุดที่อยูบ่ นแกนจะไม่เคลื่อนที่
• มุมที่จะใช้ หมุนส่วนใหญ่จะใช้ สญ
ั ลักษณ์ θ
การหมุนรอบแกน z
•
•
•
•
แกน z คือเซตของพิกดั ต่างๆ ที่อยูใ่ นรูป (0, 0, t)
สามารถระบุได้ ด้วยเวกเตอร์ (0,0,1)
สัญลักษณ์ R ,0,0,1
ส่งพิกดั  x  ไปยังพิกดั  x cos  y sin  
 y
 x sin   y cos 
 


z


z
 


1
1 


การหมุนรอบแกน z (ต่อ)
• มี matrix เป็ น
cos
 sin 

 0

 0
 sin 
cos
0
0
0
0
1
0
0

0
0

1
การหมุนรอบแกน x
•
•
•
•
แกน x คือเซตของพิกดั ต่างๆ ที่อยูใ่ นรูป (t, 0, 0)
สามารถระบุได้ ด้วยเวกเตอร์ (1,0,0)
สัญลักษณ์ R ,1,0,0
ส่งพิกดั  x  ไปยังพิกดั 
x

 y
 y cos  z sin  
 


z
 y sin   z cos 
 


1
1 


การหมุนรอบแกน x (ต่อ)
• มี matrix เป็ น
0
1
0 cos

0 sin 

0
0
0
 sin 
cos
0
0

0
0

1
การหมุนรอบแกน y
•
•
•
•
แกน z คือเซตของพิกดั ต่างๆ ที่อยูใ่ นรูป (0, t, 0)
สามารถระบุได้ ด้วยเวกเตอร์ (0,1,0)
สัญลักษณ์ R ,0,1,0
ส่งพิกดั  x  ไปยังพิกดั  z sin   x cos 
 y


y
 


z
 z cos  x sin  
 


1
1 


การหมุนรอบแกน y (ต่อ)
• มี matrix เป็ น
 cos
 0

 sin 

 0
0 sin 
1
0
0 cos
0
0
0

0
0

1
การหมุนรอบแกนใดๆ
• สัญลักษณ์ R ,a,b,c
• มี matrix เป็ น
 a 2 (1  C )  C ab(1  C )  cS ac(1  C )  bS

2
ba
(
1

C
)

cS
b
(1  C )  C bc(1  C )  aS

ca(1  C )  bS cb(1  C )  aS c 2 (1  C )  C

0
0
0

เมื่อ C  cos  และ S  sin 
0

0
0

1
การแปลง affine
• การแปลง affine คือการแปลงที่สามารถเขียนอยูใ่ นรูป matrix
a
b

c

0
d
e
f
0
i l

j m
k n

0 1
ระบบพิกดั
• ระบบพิกดั เป็ นตัวกาหนดว่าพิกดั ใดแทนจุดใด
• พิกดั และจุด?
– พิกดั คือลาดับของเลขสามตัว: (x,y,z)
– จุดคือจุดที่เราเห็นด้ วยตา
• ระบบพิกดั ในสามมิตมิ ีสว่ นประกอบอยูส่ ามส่วน
– จุดออริจิน o: จุดนี ้จะแทนด้ วยพิกดั (0,0,0) ในระบบพิกดั
– เวกเตอร์ สามตัว i, j, และ k สาหรับกาหนดทิศทางแกน x, y, และ z
ตามลาดับ
ระบบพิกดั (ต่อ)
• พิกดั (x,y,z) ในระบบพิกดั นี ้จึงหมายถึงจุด
o + xi + yj + zk
กล่าวคือมันคือจุดที่อยูห่ ่างจากจุด o
ไปตามแนวเวกเตอร์ i เป็ นระยะ x เท่าของความยาวเวกเตอร์ I
ไปตามแนวเวกเตอร์ j เป็ นระยะ y เท่าของความยาวเวกเตอร์ j
ไปตามแนวเวกเตอร์ k เป็ นระยะ z เท่าของความยาวเวกเตอร์ k
ระบบพิกดั
• เขียนได้ อีกแบบหนึง่ ว่าพิกดั (x,y,z) หมายถึงจุด
i
 x
 y
j k o  
z
 
1 
ระบบพิกดั กับการแปลง
• พิจารณาการแปลง affine
a d
b e
M 
c f

0 0
i l

j m
k n

0 1
ระบบพิกดั กับการแปลง (ต่อ)
• มันส่งพิกดั  x  ไปยังพิกดั
 y
 
z
 
1 
 ax  dy  iz  l 
bx  ey  jz  m 


 cx  fy  kz  n 


1


ระบบพิกดั กับการแปลง (ต่อ)
• พูดได้ อีกอย่างหนึง่ คือ M ส่งจุด
i
 x
 y
j k o  
z
 
1 
ไปยังจุด
i
 ax  dy  iz  l 
bx  ey  jz  m
  i
j k o 
 cx  fy  kz  n 


1


a d
b e
j k o 
c f

0 0
i l   x
j m  y 
k n z
 
0 1  1 
ระบบพิกดั กับการแปลง (ต่อ)
• แต่เราอาจมองได้ อีกว่า
i
a d
b e
j k o 
c f

0 0
i l   x
j m  y 
k n z
 
0 1  1 
มีคา่ เท่ากับ
 x
 y
ai  bj  ck di  ej  fk ii  jj  kk o  li  mj  nk  
z
 
1 
ระบบพิกดั กับการแปลง (ต่อ)
• ดังนันการแปลง
้
M จึงสามารถมองได้ วา่ เป็ นการเปลี่ยนระบบพิกดั
จากระบบพิกดั ที่
– มี o เป็ นจุดออริ จิน
– มี i เป็ นตัวกาหนดทิศทางแกน x
– มี j เป็ นตัวกาหนดทิศทางแกน y
– มี k เป็ นตัวกาหนดทิศทางแกน z
เป็ นระบบพิกดั ที่
– มี o+li+mj+nk เป็ นจุดออริ จิน
– มี ai+bj+ck เป็ นตัวกาหนดทิศทางแกน x
– มี di+ej+fk เป็ นตัวกาหนดทิศทางแกน y
– มี ii+jj+kk เป็ นตัวกาหนดทิศทางแกน z
ระบบพิกดั กับการแปลง (ต่อ)
• หรื อกล่าวได้ อีกอย่างหนึง่ คือ
– จุดออริจินใหม่คือจุดที่มีพิกดั (l,m,n) ในระบบพิกดั เดิม
– เวกเตอร์ แกน x ใหม่ คือเวกเตอร์ (a,b,c) ในระบบพิกดั เดิม
– เวกเตอร์ แกน y ใหม่ คือเวกเตอร์ (d,e,f) ในระบบพิกดั เดิม
– เวกเตอร์ แกน z ใหม่ คือเวกเตอร์ (i,j,k) ในระบบพิกดั เดิม
ระบบพิกดั กับการแปลง (ต่อ)
a
b

c

0
d
e
f
0
i l

j m
k n

0 1
แกน x ใหม่
ระบบพิกดั กับการแปลง (ต่อ)
a
b

c

0
d
e
f
0
i l

j m
k n

0 1
แกน y ใหม่
ระบบพิกดั กับการแปลง (ต่อ)
a
b

c

0
d
e
f
0
i l

j m
k n

0 1
แกน z ใหม่
ระบบพิกดั กับการแปลง (ต่อ)
a
b

c

0
d
e
f
0
i l

j m
k n

0 1
จุด origin ใหม่
Homogeneous Coordinate กับเวกเตอร์
• Homogeneous coodinate สามารถใช้ แทนได้ ทงจุ
ั ้ ดและ
เวกเตอร์
• ถ้ า w ใน (x,y,z,w) เป็ น 1 แสดงว่ามันแทนจุด
– ถ้ ามันไม่ใช่ 1 ให้ เอา w ไปหาทุกตัวเพื่อทาให้ มนั เป็ น 1 เสีย
• ถ้ า w ใน (x,y,z,w) เป็ น 0 แสดงว่ามันแทนเวกเตอร์ (ทิศทาง)
จุดกับเวกเตอร์
• จุด คือ “ตาแหน่ง”
• เวกเตอร์ คือ “ทิศทาง”
• คุณเอาเวกเตอร์ สองเวกเตอร์ มาบวกกันได้
v2
v1
v3  v1  v2
จุดกับเวกเตอร์ (ต่อ)
• แต่คณ
ุ เอาจุดสองจุดมาบวกกันไม่ได้
p1  p2  ???
p2
p1
• แต่เอาจุดมาบวกกันเวกเตอร์ ได้ จะได้ จดุ อีกจุดหนึง่
v
p1
p2
p1  v  p2
จุดกับเวกเตอร์ (ต่อ)
• ในทานองเดียวกัน คุณสามารถหาผลต่างของจุดได้ ซึง่ จะได้ ผลลัพธ์
ออกมาเป็ นเวกเตอร์
v
p2
p1
• ยกตัวอย่างเช่น 3 3 0
 4  2  2
     
 5  1   3 
     
1  1   0 
p1  v  p2
จุดกับเวกเตอร์ (ต่อ)
• การแปลง affine มีผลต่อจุดและเวกเตอร์ ตา่ งกัน
a d
b e

c f

0 0
i l   x   (ax  dy  iz )  l 
j m  y  (bx  ey  jz )  m

k n   z   (cx  fy  kz)  n 
  

0 1  1  
1

แต่
a d
b e

c f

0 0
i l   x   ax  dy  iz 
j m  y  bx  ey  jz 

k n   z  cx  fy  kz 
  

0 1  0 
0

จุดกับเวกเตอร์ (ต่อ)
• ให้
– M เป็ นการแปลง affine
– p เป็ นจุด
– ให้ v เป็ นเวกเตอร์
• ได้ วา่
– Mp เป็ นจุด
– Mv เป็ นเวกเตอร์
• ในการแปลงจุดจะมีการเลื่อนแกนขนานติดมาด้ วย
• แต่ในการแปลงเวกเตอร์ จะไม่มีการเลื่อนแกนขนานติดมาด้ วย
TRANSFORMATIONS IN THE
GRAPHICS PIPELINE
OpenGL Vertex Transformations
• ลาดับของ transform ที่ vertex หนึง่ จะต้ องผ่านไปก่อนที่มนั จะ
ถูกเปลี่ยนเป็ น fragment
OpenGL Vertex Transformation (ต่อ)
 xw  




  xo 
 y   Viewport  Perspective  Projection  View   Model   y 
 w  




 o
 0  T ransform  Divide  T ransform T ransform T ransform  zo 
  




 
1
  




 1 
Modeling Transform
• Object space คือระบบพิกดั ที่ศิลปิ นทาการขึ ้นโมเดลมาให้
• World space คือระบบพิกดั กลางของฉากที่โมเดลหลายๆ โมเดล
มาอยูร่ ่วมกัน
• Modeling transform ทาหน้ าที่เปลี่ยน vertex จากที่อยูใ่ น
object space มาอยูใ่ น world space
• ในขณะเดียวกันมันอาจจะเปลี่ยนแปลงหน้ าตาหรื อท่าทางของโมเดลได้
ด้ วย
Modeling Transform (ต่อ)
View Transform
• View transform ใช้ ในการเซตมุมกล้ อง
• Eye space คือระบบพิกดั ที่
– ตาเราอยูท่ ี่จดุ (0,0,0)
– เรามองไปในทิศทางแกน z ทางลบ (ในทิศทางของเวกเตอร์ –k)
– ทิศทางแกน y คือ “ด้ านบน”
• View transform เปลี่ยน vertex ที่อยูใ่ น world space
มาอยูใ่ น eye space
View Transform (ต่อ)
View Transform (ต่อ)
eye
point
lookat
point
y
y
x
x
z
Modelview Matrix
• OpenGL รวมขันตอนการท
้
า modeling transform และ
view transform เข้ าด้ วยกันเป็ นขันตอนเดี
้
ยว
• แทนการแปลงจาก object space ไปเป็ น eye space ด้ วย
modelview matrix

 
 Modelview  

 

 





View   Model 
 

การจัดการกับ Modelview Matrix
• เปลี่ยน mode ของ matrix เป็ น modelview matrix ด้ วย
คาสัง่ glMatrixMode(GL_MODELVIEW)
• หลังจากนันใช้
้ คาสัง่ อื่นๆ
– glLoadIdentity
– glTranslate[fd]
– glScale[fd]
– glRotate[fd]
– glMultMatrix[fd]
คาสัง่ เกี่ยวกับ matrix
• glLoadIdentity()
– ทาให้ คา่ ของ matrix ใน mode ปั จจุบนั ที่ OpenGL จาไว้ เป็ น
identity matrix
• glTranslate[fd](a,b,c)
– สมมติวา่ matrix ใน mode ปั จจุบนั คือ M
– คาสัง่ นี ้จะทาให้ matrix ปั จจุบนั กลายเป็ น MTa,b,c
• glScale[fd](a,b,c)
– คาสัง่ นี ้จะทาให้ matrix ปั จจุบนั กลายเป็ น MSa,b,c
คาสัง่ เกี่ยวกับ matrix (ต่อ)
• glRotate[fd](a, x, y, z)
– a คือ มุมที่จะหมุน หน่วยเป็ นองศา (ไม่ใช่เรเดียน!)
– x, y, และ z ระบุแกนที่จะหมุน
– คาสัง่ นี ้จะทาให้ matrix ปั จจุบนั กลายเป็ น MRa,x,y,z
คาสัง่ เกี่ยวกับ matrix (ต่อ)
• glMultMatrix[fd](m)
– m คือ list ของเลข 16 ตัว
– สมมติวา่ ให้ m = [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p]
– คาสัง่ นี ้จะทาให้ matrix ปั จจุบนั กลายเป็ น
a
b
M
c

d
e
f
g
h
i m

j n
k o

l p
LookAt Transform
• การเซตมุมกล้ องอย่างง่ายแบบหนึง่
• บอก
– eye = ตาแหน่งของตา
– at = ตาแหน่งที่ตามอง
– up = ทิศทางด้ านบน
การเปลี่ยนระบบพิกดั ของ LookAt Transform
Eye Space
y
World
Space
eye
point
at
point
up
y
x
z
z
x
gluLookAt
• gluLookAt(eyeX, eyeY, eyeZ, atX, atY, atZ, upX,
upY, upZ)
– คูณ matrix ของ mode ปั จจุบนั ด้ วย matrix ที่ transform
ระบบพิกดั โดยทาให้
• จุด (0,0,0) ในระบบพิกดั ใหม่คือจุด eye
• ทิศทาง –z ของระบบพิกดั ใหม่คือทิศทางจากจุด eye ไปยังจุด at
– กล่าวคือแกน z มีทิศทางเดียวกับเวกเตอร์ eye – at
• ทิศทางของแกน y จะคล้ ายๆ กับทิศทาง up
ตัวอย่าง
• ต้ องการเซตมุมกล้ องให้ กล้ องอยูท่ ี่จดุ (-5,-5,-5) แล้ วมองไปที่จดุ
(0,0,0) และมีเวกเตอร์ (1,-1,0) เป็ นด้ านบน
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(-5,-5,-5,0,0,0,1,-1,0);
(วาดรูปอะไรอย่างอื่นต่อไป)
Projection Transformation
• เปลี่ยน eye space เป็ น clip space
• พิกดั ใน clip space จะใช้ เป็ นตัวบอกว่าเราจะเห็น vertex ใด
หรื อไม่เห็น vertex ใด
• กระบวนการตัดสินใจ: vertex ที่เห็นจะต้ องมี
– -1 ≤ x ≤ 1
– -1 ≤ y ≤ 1
– -1 ≤ z ≤ 1
• Projection transform ยังมีผลต่อลักษณะภาพที่เราเห็นอีก
ด้ วย
Projection Transform ใน OpenGL
• OpenGL จะจา matrix ของ projection transform
เอาไว้
• เวลาต้ องการเปลี่ยนแปลง projection matrix ให้ เปลี่ยน
mode ของ matrix เป็ น GL_PROJECTION ด้ วยคาสัง่
glMatrixMode(GL_PROJECTION);
• หลังจากนันใช้
้ คาสัง่ ในการเปลี่ยนแปลง matrix อื่นแบบเดิม เช่น
glLoadIdentity(), glMultMatrix(…), ฯลฯ
• ส่วนมากเราจะสัง่ glLoadIdentity() ทันทีหลังจากสัง่
glMatrixMode(GL_PROJECTION) เสร็จแล้ ว เพื่อเคลียร์
ค่า projection matrix ก่อนใส่คา่ ใหม่
Projection Transformation ที่สาคัญ 2 แบบ
• Orthographic Projection
• Perspective Projection
Orthographic Projection
• ปริมาตรของบริเวณที่เห็นเป็ นปริซมึ
• ไม่มี foreshortening กล่าวคือ ไม่วา่ วัตถุจะอยูใ่ กล้ ไกลก็เห็น
ขนาดเท่ากันหมด
• หลังจากฉาก เส้ นขนานยังเป็ นเส้ นขนานอยู่
• ใช้ ในโปรแกรมช่วยเขียนแบบ/CAD เนื่องจากขนาดของวัตถุเป็ นเรื่ อง
สาคัญ
Orthographic Projection (ต่อ)
http://www2.arts.ubc.ca/TheatreDesign/crslib/drft_1/orthint.htm
Orthographic Projection (ต่อ)
http://www2.arts.ubc.ca/TheatreDesign/crslib/drft_1/cad/wdstv.htm
การนิยาม Orthographic Projection
• นิยามได้ โดยการนิยามปริ ซมึ ของปริ มาตรที่เราต้ องการมองเห็น
• ปริ ซมึ นี ้สามารถนิยามได้ ด้วยตัวเลข 3 คู่
– left และ right --- ขอบเขตในแนวแกน x
– top และ bottom --- ขอบเขตในแนวแกน y
– near และ far --- ขอบเขตในแนวแกน -z (เพราะเรามองในแนว -z)
• ค่าทังหกเป็
้
นพิกดั ใน eye space
• ปริ ซมึ ที่นิยามคือ
{(x,y,z) : left ≤ x ≤ right, top ≤ y ≤ bottom,
near ≤ -z ≤ far}
ปริ ซึมปริ มาตรที่มองเห็น
การนิยาม Orthographic Projection (ต่อ)
• Matrix ของ orthographic projection ต้ องทาอะไรบ้ า
– ส่ง x = left ไป x = -1
– ส่ง x = right ไป x = 1
– ส่ง y = bottom ไป y = -1
– ส่ง y = top ไป y = 1
– ส่ง z = -far ไป z = 1
– ส่ง z = -near ไป z = -1
Matrix ของ Orthographic Projection
 2
r  l

 0

 0

 0

0
0
2
t b
0
0
0
2
f n
0
r l 

r l 

t b


t b 
f  n

f  n

1 
คาสัง่ OpenGL เกี่ยวกับ
Orthographic Projection
• glOrtho(left, right, bottom, top, near, far)
– คูณ matrix ปั จจุบนั ด้ วย matrix ของ orthographic
projection ในหน้ าก่อน
– ก่อนใช้ ควรเรี ยก
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
ก่อนเพื่อเปลี่ยน mode และเคลียร์ คา่ projection matrix เดิม
• glOrtho2D(left, right, bottom, top)
– เหมือนกับ glOrtho แต่ให้ คา่ near เป็ น 0 และ ค่า far เป็ น 1
Perspective Projection
•
•
•
•
ปริมาตรของบริเวณที่เห็นเป็ น frustum (ปี ระมิดยอดตัด)
มี foreshortening กล่าวคือ อะไรที่อยูใ่ กล้ จะเห็นใหญ่กว่า
หลังจากฉายแล้ ว เส้ นขนานอาจจะไม่ขนานกันเหมือนเดิม
ให้ ความเป็ นสามมิติ เพราะเหมือนกับที่ตาคนทางาน ทาให้ เหมือนเข้ า
ไปอยูใ่ นฉากจริงๆ
• ใช้ กบั โปรแกรมทางความบันเทิง
Perspective Projection (ต่อ)
Perspective Projection (cont.)
orthographic
perspective
การนิยาม Perspective Projection
• นิยามด้ วยเลข 6 ตัวเหมือนกับ orthographic projection
การนิยาม Perspective Projection (ต่อ)
• ปริมาตรที่มองเห็นคือปี ระมิดยอดตัดที่มียอดเป็ นสี่เหลีย่ ม
{(x,y,z) : left ≤ x ≤ right, bottom ≤ y ≤ top,
z = -near}
ซึง่ ยอดของมันถูกฉายต่อไปจนถึง z = -far
การนิยาม Perspective Projection (ต่อ)
• ให้ จดุ (x,y,z) มาใน eye space แล้ วมันจะถูกแปลงเป็ นอะไรใน
clip space?
xclip  1
xclip  1
zeye   f
(x,y,z)
zeye  z
zeye  n
xeye  l
xeye  r
(0,0,0)
การนิยาม Perspective Projection (ต่อ)
• หา x ใน clip space
xclip  1
xclip  ??? x  1
clip
zeye   f
(x,y,z)
zeye  z
zeye  n
xeye  l
xeye  r
(0,0,0)
การนิยาม Perspective Projection (ต่อ)
• เริ่มจากการหา x ใน eye space ของจุดปลายสองจุด
xclip  1
xeye,left  ???
xclip  ??? x  1
clip
(x,y,z)
xeye,right
zeye   f
 ???
zeye  z
zeye  n
xeye  l
xeye  r
(0,0,0)
การนิยาม Perspective Projection (ต่อ)
• อาศัยความรู้เรื่ องสามเหลี่ยมคล้ าย ได้ วา่
zr
ดังนัน้ xeye,right   n
xeye,right
r
z

n
xeye,right  ???
zeye  z
zeye  n
xeye  r
(0,0,0)
การนิยาม Perspective Projection (ต่อ)
• ทานองเดียวกัน
xeye,left
l
z

n
xeye,left  ???
ดังนัน้
xeye,left
zl

n
zeye  z
zeye  n
xeye  l
(0,0,0)
การนิยาม Perspective Projection (ต่อ)
• เรารู้วา่ xclip  ax  b สาหรับค่าคงที่ a และ b บางตัว
xclip  1 xclip  ??? xclip  1
(x,y,z)
xeye,left
zl

n
zeye  z
xeye,right
(0,0,0)
zr

n
การนิยาม Perspective Projection (ต่อ)
• เนื่องจากถ้ า x = -zl/n แล้ ว xclip = -1
และถ้ า x = -zr/n แล้ ว xclip = 1
• ได้ วา่
zl
 1  a
b
n
zr
1  a  b
n
• เมื่อแก้ สมการออกมาจะได้ วา่
2n
(r  l ) z
r l
b
r l
a
การนิยาม Perspective Projection (ต่อ)
• กล่าวคือ
2n
r l
xclip  
x
(r  l ) z
r l
• ในทานองเดียวกันเราก็จะได้ วา่
2n
t b
yclip  
y
(t  b) z
t b
การนิยาม Perspective Projection (ต่อ)
• แล้ ว zclip ควรจะมีคา่ เท่าไหร่?
• ค่า zclip จะถูกใช้ เป็ น “ความลึก” ของ fragment
• zclip จะต้ องมีคณ
ุ สมบัติสองประการ
– ถ้ า z น้ อย zclip ก็ต้องน้ อยตามไปด้ วย
– perspective matrix จะต้ องส่งเส้ นตรงไปยังเส้ นตรง
• ตัวอย่าง zclip ที่ใช้ ไม่ได้
– zclip=z
– zclip 
x y z
2
2
2
การนิยาม Perspective Projection (ต่อ)
• zclip ที่ OpenGL ใช้ มีรูป
B
z clip  A 
z
• เนื่องจาก zclip= -1 ถ้ า z = -n
และ zclip= 1 ถ้ า z = -f
จะได้ วา่
B
1  A 
n
B
1 A
f
การนิยาม Perspective Projection (ต่อ)
• เมื่อแก้ สมการออกมาแล้ วจะได้ วา่
• กล่าวคือ
2 fn
B
f n
f n
A
f n
f n
2 fn
zclip 

f  n ( f  n) z
การนิยาม Perspective Projection (ต่อ)
• กล่าวคือ perspective projection matrix จะต้ องส่ง
x
 y
 
z
 
1 
ไปยัง
2n
r  l   2n

r l 

x

x
z 
 (r  l ) z


r l
r l

  r l

2
n
t

b
2
n
t

b

 
y
y
z 
 (t  b) z
t b   t b
t b 
 f n
2 fn   f  n z  2 fn 


  f n

f

n
f

n
(
f

n
)
z

 


z
1


 
Matrix ของ Perspective Projection
 2n
r  l

 0

 0

 0

0
2n
t b
0
0
r l
r l
t b
t b
f n

f n
1

0 

0 

2 fn 

f  n

0 
คาสัง่ OpenGL เกี่ยวกับ
Perspective Projection
• glFrustum(left, right, bottom, top, near, far)
– คูณ matrix ปั จจุบนั ด้ วย matrix ของ perspective
projection ในหน้ าก่อน
– ก่อนใช้ ควรเรี ยก
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
ก่อนเพื่อเปลี่ยน mode และเคลียร์ คา่ projection matrix เดิม
คาสัง่ OpenGL เกี่ยวกับ
Perspective Projection (ต่อ)
• gluPerspective(fovy, aspect, near, far)
– คูณ matrix ปั จจุบนั ด้ วย perspective projection matrix
เช่นเดียวกับ glFrustrum
– มีผลเหมือนกับสัง่ glFrustum โดยได้
•
•
•
•
top = near * tan(fovy / 2)
bottom = -top
right = aspect * top
left = -right
คาสัง่ OpenGL เกี่ยวกับ
Perspective Projection (ต่อ)
– fovy ย่อมาจาก field of view Y หมายถึงความกว้ างของมุมมองตาม
แนวแกน y (มีหน่วยเป็ นองศา)
– aspect คือ aspect ratio ของหน้ าตัดของปี ระมิด
– ปี ระมิดที่ gluPerspective สร้ างมีหน้ าตาเป็ นดังข้ างล่าง
คาสัง่ OpenGL เกี่ยวกับ
Perspective Projection (ต่อ)
• สังเกตว่าคาสัง่ glFrustum สามารถสร้ างปี ระมิดที่ไม่สมมาตรรอบ
แกน z ได้
• แต่ปีระมิดที่สร้ างด้ วย gluPerspective จะเป็ นปี ระมิดที่สมมาตร
รอบแกน z เสมอ
TRANSFORMATIONS IN MODELING
การแปลงกับการวาดภาพ
• การแปลงสามารถนามาใช้ สร้ างภาพที่มีความซับซ้ อนได้ มากมาย
• เราจะมาดูตวั อย่างการสร้ าง แฟรกตัล (fractal)
– รูปที่พอเอาแว่นขยายส่องดูแล้ วเห็นเป็ นลักษณะเหมือนกับตอนไม่ได้ ใช้ แว่น
ขยายดู
Sierpinski Triangle
Sierpinski Triangle
• เพื่อความง่ายในการสร้ าง เราจะแบ่ง Sierpinski triangle
ออกเป็ นชันๆ
้
• ชันที
้ ่ 0 เป็ นสามเหลี่ยมด้ านเท่าธรรมดา
Sierpinski Triangle
• ชันที
้ ่ 1 เกิดจากการเอา Sierpiński triangle ชันที
้ ่ 0 ที่
ย่อส่วนลงสองเท่ามาเรี ยงกันตามรูปข้ างล่างนี ้
Sierpinski Triangle
• Sierpiński Triangle ชันที
้ ่ 2 เกิดจากการเอา Sierpiński
triangle ชันที
้ ่ 1 ที่ยอ่ ส่วนลงสองเท่ามาเรี ยงกันตามรูปข้ างล่างนี ้
Sierpinski Triangle
• Sierpiński Triangle ชันที
้ ่ 3 เกิดจากการเอา Sierpiński
triangle ชันที
้ ่ 2 ที่ยอ่ ส่วนลงสองเท่ามาเรี ยงกันตามรูปข้ างล่างนี ้
Sierpinski Triangle
• Sierpiński Triangle ชันที
้ ่ k เกิดจากการเอา Sierpiński
triangle ชันที
้ ่ k-1 ที่ยอ่ ส่วนลงสองเท่ามาเรี ยงกันตามรู ปเดิม
• ข้ างล่างนี ้คือ Sierpiński triangle ประมาณชันที
้ ่8
เราจะวาด Sierpinski Triangle ได้อย่างไร?
• เขียนฟั งก์ชนั void draw_sierpinski(int k) ที่ทาการวาด
Sierpinski Triangle ชันที
้ ่k
• มีกฎอยูส่ องข้ อในการวาด Sierpinski Triangle
– ถ้ า k = 0 ให้ วาดสามเหลี่ยมด้ านเท่า
– ถ้ า k > 0 ให้ วาด Sierpinski Triangle ชันที
้ ่ k-1 สามอันเรี ยงกัน
ตามรูปที่เราเคยเห็นมา
วาดสามเหลี่ยมด้านเท่า
• ต้ องการวาดสามเหลี่ยมด้ านเท่าความยาวด้ านละ 1 หน่วย
• จุดศูนย์กลาง (จุด centroid) อยูท่ ี่จดุ (0,0)
¡
¡
¡
1
p1
;
2 2 3
¢
0;
p1
3
¢
¡1
p1
2; 2 3
¢
วาดสามเหลี่ยมด้านเท่า
void draw_triangle()
{
glBegin(GL_LINE_LOOP);
glVertex2d( 0.0, 1.0/sqrt(3.0));
glVertex2d( 0.5, -0.5/sqrt(3.0));
glVertex2d(-0.5, -0.5/sqrt(3.0));
glEnd();
}
ผลลัพธ์
ฟังก์ชนั draw_sierpinski
void draw_sierpinski(int k)
{
if (k == 0)
draw_triangle();
else
{
//
//
}
}
วาด Sierpinski
ชัน้ ที่ k-1 สามอัน
triangle
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• วาดอย่างไร?
– เรี ยก draw_sierpinski(k-1)
• วาดตรงไหน?
¡
cent roid = 0; 2
cent roid =
¡
¡
1
p1
4; ¡ 4 3
¢
p1
¢
3
cent roid =
¡1
4; ¡
p1
4 3
¢
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• วาด Sierpinski Triangle อันบน
¡
¢
– Translate centroid ไปเป็ นจุด 0;
– Scale ขนาดลดลง 2 เท่า (= ขยาย 0.5 เท่า)
p1
2 3
• วาด Sierpinski Triangle อันล่างขวา
¡1
– Translate centroid ไปเป็ นจุด 4 ; ¡
– Scale ขนาดลดลง 2 เท่า (= ขยาย 0.5 เท่า)
p1
4 3
¢
• วาด Sierpinski Triangle อันล่างซ้ าย
¡
– Translate centroid ไปเป็ นจุด ¡
– Scale ขนาดลดลง 2 เท่า (= ขยาย 0.5 เท่า)
1
p1
4; ¡ 4 3
¢
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
void draw_sierpinski(int k)
{
if (k == 0)
draw_triangle();
else
{
glLoadIdentity();
glTranslated(0.0, 0.5 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
glLoadIdentity();
glTranslated(0.25, -0.25 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
glLoadIdentity();
glTranslated(-0.25, -0.25 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
}
}
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• draw_siepinski(0)
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• draw_siepinski(1)
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• draw_siepinski(2)
วาด Sierpinski Triangle ชั้นที่ k-1 สามอัน
• draw_siepinski(2)
เกิดอะไรขึ้น?
ระบบพิกดั สาหรับวาด Siepinski triangle ระดับ k = I
เกิดอะไรขึ้น?
ระบบพิกดั สาหรับวาด
Siepinski triangle บน
คือ TUS0.5 =MU
ระบบพิกดั สาหรับวาด
Siepinski triangle ซ้ าย
คือ TLS0.5 =ML
ระบบพิกดั สาหรับวาด
Siepinski triangle ขวา
คือ TRS0.5 =MR
เกิดอะไรขึ้น?
MUMU
MUML
MLMU
MLML
MLMR
MUMR
MRMU
MRML
MRMR
พิจารณา code ใหม่อีกครั้ง
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
MODELVIEW = M
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
MODELVIEW = ???
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
พิจารณา code ใหม่อีกครั้ง
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
MODELVIEW = M
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
MODELVIEW = ???
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
ความจริงแล้ ว MODELVIEW ควรมีค่าเท่ ากับ MTS!!!
พิจารณา code ใหม่อีกครั้ง
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
glLoadIdentity();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
MODELVIEW = M
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
MODELVIEW = ???
MODELVIEW = ???
MODELVIEW = I
MODELVIEW = T
MODELVIEW = TS
MODELVIEW = ???
ตรงจุดสองจุดนี ้ MODELVIEW ควรมีค่าเท่ ากับ M
แล้วจะต้องทาอะไร?
• ก่อนสัง่ glTranslated(…) ต้ องมีการจาค่าเมตริกซ์
MODELVIEW อันเดิมเอาไว้
• หลังเรี ยก draw_sierpinski(…) ต้ องมีการเอาค่า
MODELVIEW อันเดิมคืนกลับมา
glPushMatrix() และ glPopMatrix()
• glPushMatrix()
– ทาการ push ค่าของเมตริกซ์ใน mode ปั จจุบนั ลง stack
• glPopMatrix()
– pop stack ที่เก็บค่าเมตริกซ์เอาไว้ แล้ วนาค่าที่ได้ ไปให้
• เราสามารถใช้ ฟังก์ชนั สองฟั งก์ชนั นี ้ในการ “จา” transform ได้
เขียนใหม่
MODELVIEW = M
glPushMatrix();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
glPopMatrix();
MODELVIEW
MODELVIEW
MODELVIEW
MODELVIEW
MODELVIEW
=
=
=
=
=
M (จา)
MT
MTS
???
M
glPushMatrix();
glTranslated(...);
glScaled(...);
draw_sierpinski(k-1);
glPopMatrix();
MODELVIEW
MODELVIEW
MODELVIEW
MODELVIEW
MODELVIEW
=
=
=
=
=
M (จา)
MT
MTS
???
M
ทั้งฟังก์ชนั
void draw_sierpinski(int k)
{
if (k == 0)
draw_triangle();
else
{
glPushMatrix();
glTranslated(0.0, 0.5 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
glPopMatrix();
glPushMatrix();
glTranslated(0.25, -0.25 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
glPopMatrix();
glPushMatrix();
glTranslated(-0.25, -0.25 / sqrt(3.0), 0.0);
glScaled(0.5, 0.5, 0.5);
draw_sierpinski(k-1);
glPopMatrix();
}
}
ผลลัพธ์
• draw_sierpinski(2)
ผลลัพธ์
• draw_sierpinski(3)
ผลลัพธ์
• draw_sierpinski(4)
ผลลัพธ์
• draw_sierpinski(8)
HIERARCHICAL
SCENE ORGANIZATION
การจัดฉาก
• ฉากประกอบด้ วยวัตถุหลายๆ อย่าง
• ศิลปิ นสร้ างวัตถุแต่ละชิ ้นขึ ้นมาใน object space ของมันเอง
• วัตถุแต่ละวัตถุจะต้ องถูกแปลงจากที่อยูใ่ น object space ให้ มาอยู่
ใน world space
ตัวอย่างฉาก
ภาพจาก Durand and Cutler, 6.837 Fall 2003 Lecture Note: Transformations 2: In Modeling
ฉากตัวอย่าง
y=1.2
y=0
(0,0)
y=-1
x=-2
x=0
x=2
วัตถุ
• สมมติวา่ ศิลปิ นสร้ างวัตถุให้ เรามาสองอย่าง
– Circle: วงกลมรัศมีหนึง่ หน่วยที่มีจดุ ศูนย์กลางอยูท่ ี่จดุ (0,0)
– Square: สี่เหลี่ยมจัตรุ ัสที่มีจดุ มุมล่างซ้ ายอยูท่ ี่จดุ (-1,-1) และมุมบน
ขวาอยูท่ ี่ (1,1)
• เราจะสร้ างฉากที่เห็นในสไลด์ที่แล้ วอย่างไร?
y
y
2
2
1
-2
1
-1
1
-1
-2
2
-2
x
-1
1
-1
-2
2
x
การจัดฉากแบบเป็ นลาดับขึ้น
• เวลาจัดฉากเรามักจะแบ่งมันเป็ นลาดับขัน้
ฉาก
เก้ าอี ้
Square
Square
โต๊ ะและถาดผลไม้
Square
Square
Square
โต๊ ะ
Square
พื ้น
ถาดผลไม้
Square
Circle
Square
Circle
วาดเก้าอี้
• เราเลือก object space ของเก้ าอี ้ให้ มมุ ล่างซ้ ายของมันอยูท่ ี่จดุ
(0,0)
y=2
y=1
(0,0)
y=0
วาดเก้าอี้
• ขาหน้ า
– ย้ ายจุดศูนย์กลางไปอยู่ที่ (0.1, 0.35)
– ขยายตามแกน x = 0.1 เท่า ตามแกน y = 0.35 เท่า
– วาด Square
• พื ้น
– ย้ ายจุดศูนย์กลางไปอยู่ที่ (0.3, 0.8)
– ขยายตามแกน x = 0.3 เท่า ตามแกน y = 0.1 เท่า
– วาด Square
• ขาหลังและพนัก
– ย้ ายจุดศูนย์กลางไปอยู่ที่ (0.7, 1.1)
– ขยายตามแกน x = 0.1 เท่า ตามแกน y = 1.1 เท่า
– วาด Square
Scene Graph
• เราสามารถแทนการแปลงและการวาดภาพในสไลด์ที่แล้ วได้ ด้วย
แผนภาพที่เรี ยกว่า scene graph
เก้ าอี ้
T0:1;0:35;0:0
T0:3;0:8;0:0
T0:7;1:1;0:0
S0:1;0:35;1:0
S0:3;0:1;1:0
S0:1;1:1;1:0
Square
Square
Square
โค้ด
• เราสามารถเปลี่ยน scene graph เป็ นโค้ ดได้ อย่างง่ายดาย
void draw_chair()
{
glPushMatrix();
glTranslated(0.1, 0.35, 0.0);
glScaled(0.1, 0.35, 1.0);
draw_square(...);
glPopMatrix();
glPushMatrix();
glTranslated(0.3, 0.8, 0.0);
glScaled(0.3, 0.1, 1.0);
draw_square(...);
glPopMatrix();
glPushMatrix();
glTranslated(0.7, 1.1, 0.0);
glScaled(0.1, 1.1, 1.0);
draw_square(...);
glPopMatrix();
}
วาดส่ วนประกอบอื่นๆ ของฉาก
• สมมติวา่ เราสร้ างฟั งก์ชนั
– draw_table() เพื่อวาดโต๊ ะ โดยที่มมุ ล่างซ้ ายของมันอยูท่ ี่จดุ (0,0)
– draw_tray() เพื่อวาดถาดผลไม้ โดยที่มมุ ล่างซ้ ายของมันอยูจ่ ดุ (0,0)
– draw_floor() เพื่อวาดพื ้น
• ฟั งก์ชนั พวกนี ้สามารถสร้ างได้ เหมือน draw_chair()
• โค้ ดจริงๆ ไปดูได้ ในโค้ ดตัวอย่าง
วาดส่ วนประกอบอื่นๆ ของฉาก
• เราสามารถวาดโต๊ ะและถาดผลไม้ ได้ ดงั ต่อไปนี ้
– วาดโต๊ ะโดยการเรี ยก draw_table()
– วาดถาดผลไม้
• ย้ ายจุดมุมซ้ ายไปอยู่ที่จดุ (0.8, 1.3)
• แล้ วเรี ยก draw_tray()
Scene Graph ของโต๊ะและถาด
โต๊ ะและถาด
โต๊ ะ
T0:8;1:3;0:0
ถาด
โค้ด
void draw_table_and_tray()
{
draw_table();
glPushMatrix();
glTranslated(0.8, 1.3, 0.0);
draw_tray();
glPopMatrix();
}
Scene Graph ของฉาก
ฉาก
T¡
1:7;¡ 1:0;0:0
พื ้น
T0:9;¡
โต๊ ะและถาด
โต๊ ะ
1:0;0:0
เก้ าอี ้
T0:1;0:35;0:0
T0:3;0:8;0:0
T0:7;1:1;0:0
S0:1;0:35;1:0
S0:3;0:1;1:0
S0:1;1:1;1:0
T0:8;1:3;0:0
ถาด
Square
Square
Square
โค้ด
void draw_scene()
{
glPushMatrix();
glTranslated(-1.7, -1.0, 0.0);
draw_table_and_tray();
glPopMatrix();
draw_floor();
glPushMatrix();
glTranslated(0.9, -1.0, 0.0);
draw_chair();
glPopMatrix();
}
ผลลัพธ์
บทเรี ยน
• เราสามารถสร้ างฉากที่มีความซับซ้ อนได้ จาก
– วัตถุง่ายๆ
– การแปลง
• เพื่อความสะดวกและความเข้ าใจง่าย เราสามารถจับกลุม่ วัตถุเป็ นกลุม่ ๆ
แล้ วสร้ างฉากจากกลุม่ ของวัตถุได้
• เราสามารถแทนการจัดฉากได้ ด้วยแผนภาพที่เรี ยกว่า scene graph ซึง่
ประกอบด้ วย
– กล่องสาหรับแทนวัตถุ
– กล่องสาหรับแทนกลุม่ ของวัตถุ
– กล่องสาหรับแทนการแปลง
บทเรี ยน
• เมื่อเขียน scene graph แล้ วเราสามารถเขียนโค้ ดเพื่อวาดฉากที่
scene graph บรรยายได้ อย่างง่ายดาย
– กล่องวัตถุหรื อกลุม่ ของวัตถุ -> ฟั งก์ชนั
– กล่องการแปลง -> การเรี ยกฟั งก์ชนั ทาการแปลง เช่น glTranslate,
glScale หรื อ glRotate
– แขนงของกล่อง -> การเรี ยก glPushMatrix() แล้ วลงไปจัดการแขนง
นัน้ แล้ วจึงเรี ยก glPopMatrix()