轉(zhuǎn)載文章一:http://www.cnblogs.com/shanhaobo/articles/1065380.html
[3D基礎(chǔ)]理解計(jì)算機(jī)3D圖形學(xué)中的坐標(biāo)系變換
要談坐標(biāo)系變換,那么坐標(biāo)系有哪些呢?依次有:物體坐標(biāo)系,世界坐標(biāo)系,相機(jī)坐標(biāo)系,投影坐標(biāo)系以及屏幕坐標(biāo)系.我要討論的就是這些坐標(biāo)系間的轉(zhuǎn)換。
這些坐標(biāo)系不是憑空而來(lái),他們都是為了完成計(jì)算機(jī)3D圖形學(xué)最最最基本的目標(biāo)而出現(xiàn).
計(jì)算機(jī)3D圖形學(xué)最最最基本的目標(biāo)就是:將構(gòu)建好的3D物體顯示在2D屏幕坐標(biāo)上.
初看好像就是將最初的物體坐標(biāo)系轉(zhuǎn)換到屏幕坐標(biāo)系就可以了呀,為什么多出了世界坐標(biāo)系,相機(jī)坐標(biāo)系,投影坐標(biāo) 系。這是因?yàn)?在一個(gè)大世界里有多個(gè)物體,而每個(gè)物體都有自己的坐標(biāo)系,如何表述這些物體間相對(duì)的關(guān)系,這個(gè)多出了世界坐標(biāo)系;如果只需要看到這個(gè)世界其 中一部分,這里就多出了相機(jī)坐標(biāo)系;至于投影坐標(biāo)系那是因?yàn)橹苯訉?D坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo)是非常復(fù)雜的(因?yàn)樗鼈儾粌H維度不同,度量不同(屏幕坐標(biāo)一般都 是像素為單位,3D空間中我們可以現(xiàn)實(shí)世界的米,厘米為單位),XY的方向也不同,在2D空間時(shí)還要進(jìn)行坐標(biāo)系變換),所以先將3D坐標(biāo)降維到2D坐標(biāo), 然后2D坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)。
理解3D圖形學(xué)的第一步:理解左手坐標(biāo)系與右手坐標(biāo)系
為什么會(huì)有左手坐標(biāo)系與右手坐標(biāo)系之分?
在3D空間(沒(méi)錯(cuò)!就是3D)中,所有2D坐標(biāo)系是等價(jià)的(就是通過(guò)一系列的仿射變換,可以互相轉(zhuǎn)換)
而3D坐標(biāo)系不是等價(jià)的,通過(guò)仿射變換,是無(wú)法將左手坐標(biāo)系轉(zhuǎn)換到右手坐標(biāo)系;也就是說(shuō),物體坐標(biāo)系用的就是左手坐標(biāo)系,世界坐標(biāo)系用的是右手 坐標(biāo)系,那么物體可能就是不會(huì)是我們所希望的樣子了,可能是倒立的,也可能是背對(duì)著我們的,所以我們要區(qū)分左手坐標(biāo)系與右手坐標(biāo)系。也許在4D空間,左右 手坐標(biāo)系就可以互相變換了吧。
進(jìn)入正題吧:
首先討論的是物體坐標(biāo)系->世界坐標(biāo)系
前面說(shuō)了為了描述多個(gè)物體間相對(duì)的關(guān)系,這里引進(jìn)了世界坐標(biāo)系,所以世界坐標(biāo)系是個(gè)參考坐標(biāo)系。
這一步的目的將所有的物體的點(diǎn)都轉(zhuǎn)移到世界坐標(biāo)系,這里主要涉及的是旋轉(zhuǎn),縮放,平移等。
不過(guò)我將詳細(xì)說(shuō)明為何及如何用矩陣來(lái)描述這些變換。
例:如果有兩個(gè)坐標(biāo)系C與C`, C`是C繞Z軸旋轉(zhuǎn)θ得到的。下面是各坐標(biāo)軸的變換:
如果是C坐標(biāo)系的點(diǎn)P(x, y, z),而在C`的表示就是

這時(shí)該如何建立矩陣呢? 答案就是區(qū)分你用的是行向量還是列向量.也許有人會(huì)問(wèn)為什么不區(qū)分是左手坐標(biāo)系還是右手坐標(biāo)系呢?因?yàn)镃可以變換到C`,那么他們一定是同在左手坐標(biāo)系或右手坐標(biāo)系,變換只能在可以互相轉(zhuǎn)換的坐標(biāo)系之間進(jìn)行。
如果你用的是行向量:由于行向量只能左乘矩陣(注意乘與乘以的區(qū)別)
所以矩陣形式應(yīng)該是這樣

只有這樣,在左乘矩陣時(shí)才能得到上面P`的形式。

如果你用的是列向量: 由于列向量只能右乘矩陣(注意乘與乘以的區(qū)別)
所以矩陣形式應(yīng)該是這樣

只有這樣,在右乘矩陣時(shí)才能得到上面P`的形式。

至于如何旋轉(zhuǎn),縮放,平移我不在多說(shuō)。
…………………………………覺(jué)得自己好像跑題了
.還好這兩個(gè)坐標(biāo)系變換很簡(jiǎn)單。
我們?cè)儆懻?span>世界坐標(biāo)系->相機(jī)坐標(biāo)系
引進(jìn)相機(jī)的目的就是只需看到世界的一部分,而哪些是可以在相機(jī)里看到的,就需要進(jìn)行篩選。將物體轉(zhuǎn)換到相機(jī)坐標(biāo)系,這樣相機(jī)坐標(biāo)系進(jìn)行篩選時(shí)就會(huì)簡(jiǎn)單很多。這里的重點(diǎn)是構(gòu)建相機(jī)坐標(biāo)系。
物體坐標(biāo)系,世界坐標(biāo)系是美工在繪制時(shí)就定義好了的。而相機(jī)坐標(biāo)系是需要程序?qū)崟r(shí)構(gòu)建的。(當(dāng)然這是通常情況下,如果你要建立一個(gè)世界,這個(gè)世界都是圍繞 你轉(zhuǎn),要實(shí)時(shí)改變所有物體坐標(biāo)系,固定相機(jī)坐標(biāo)系(其實(shí)這時(shí)候相機(jī)坐標(biāo)系就是世界坐標(biāo)系),建立一個(gè)地心說(shuō)的世界,我也沒(méi)辦法,你的思維也太不一樣了。)
如何構(gòu)建相機(jī)坐標(biāo)系呢?首先我們要明確目標(biāo):我們是要構(gòu)建3D坐標(biāo)系(好像是廢話),三個(gè)坐標(biāo)軸要互相垂直(也好像是廢話).
我們一般用UVN相機(jī)。例如:D3D的D3DXMatrixLookAtLH,D3DXMatrixLookAtRH,OGL的gluLookAt(右手坐標(biāo)系).
如何建立呢UVN相機(jī)呢? 我們就要利用叉積這個(gè)工具了:兩個(gè)不平行,不重疊的向量的叉積可以得到與這兩個(gè)向量互相垂直的向量。
如果有了相機(jī)的位置與目標(biāo)的位置那么我們可以確定一個(gè)Z軸(有人問(wèn)為什么是Z軸,因?yàn)槲矬w的遠(yuǎn)與近我們就習(xí)慣用Z值來(lái)表示的)。求Z軸時(shí)要注意 是左手坐標(biāo)系還是右手坐標(biāo)系,左右手坐標(biāo)系XY軸方向相同時(shí),Z軸的方向相反。所以左手坐標(biāo)系是目標(biāo)位置減去相機(jī)位置,而右手坐標(biāo)系則是相機(jī)位置減去目標(biāo) 位置。記得normalize
這是我們要得到X與Y軸了。如何求X,Y軸呢?
一般方法是:
1、選擇一個(gè)臨時(shí)Y軸,
2、對(duì)臨時(shí)Y 與Z 軸進(jìn)行叉積求得一個(gè)X軸
3、X軸再與Z軸進(jìn)行叉積,得到一個(gè)Y軸。
有了XYZ就可以求出旋轉(zhuǎn)的相機(jī)矩陣了。
如何選擇一個(gè)Y軸呢?大多數(shù)情況下是(0,1,0),但是如果是相機(jī)位置E與目標(biāo)位置T垂直,即(E-T=(0,+/-1,0)時(shí)),這時(shí)就不能用(0,1,0)了, 因?yàn)閮蓚€(gè)平行向量的叉積是零向量,所以我們就要另選一個(gè)Y軸。
但是我覺(jué)得我們可以改變方法。
如果不能選Y軸,我們就選擇一個(gè)臨時(shí)X軸,這個(gè)臨時(shí)X軸就是(1,0,0)。
然后再對(duì)臨時(shí)X軸與Z軸進(jìn)行叉積求得一個(gè)Y軸。
最后Y軸再與Z軸進(jìn)行叉積,得到X軸。
這樣可以得到XYZ軸。
最后再根據(jù)行向量與列向量建立相機(jī)矩陣,再進(jìn)行平移。
相機(jī)坐標(biāo)系->投影坐標(biāo)系.
投影的目的就是:降維.
兩種投影方式:正交投影與透視投影.
在我們TEAM中易穎已經(jīng)寫(xiě)了,我就不多說(shuō)了,大家去看他的文章。
投影坐標(biāo)系->屏幕坐標(biāo)系
這是最簡(jiǎn)單的。2D坐標(biāo)變換。也不多說(shuō)。
轉(zhuǎn)載文章2:http://www.xingousi.com/computer/computergraphics.htm
計(jì)算機(jī)圖形學(xué)筆記(Part 1 ):計(jì)算機(jī)圖形學(xué)透視投影變換原理及一點(diǎn)和兩點(diǎn)透視
一、平行互分法
吳英凡所寫(xiě)的《透視作圖的新方法——交點(diǎn)法體系》,其中談到的平行互分法,還是有道理的。
其實(shí)簡(jiǎn)單點(diǎn)說(shuō),就是透視圖上的兩條“原來(lái)空間中的平行線”(在畫(huà)面上透視投影為相交于滅點(diǎn)),通過(guò)其中一條透視投影直線的端點(diǎn)畫(huà)另一條透視投影直線的平行線,必平行于畫(huà)面;這第三條線在畫(huà)面的透視投影的滅點(diǎn)必然在另一條透視投影線上。
二、透視投影變換學(xué)習(xí)總結(jié)
1、用多維數(shù)列表示低維空間坐標(biāo),加深理解齊次坐標(biāo)表示法。
齊次坐標(biāo)表示法可以方便地運(yùn)算,同時(shí)形狀不變。[x,y,z,0]表示一個(gè)無(wú)窮的點(diǎn)。
2、透視投影變換公式可以看成兩個(gè)矩陣的乘積,其中一個(gè)做透視變換,另外一個(gè)作正投影
保留的z'值的確切含義:指的是在完全作完透視投影變換之前,僅作透視投影之后的一條線.
它的幾何意義見(jiàn)李建平《計(jì)算機(jī)圖形學(xué)原理教程》第44頁(yè)。
3、左手和右手坐標(biāo)系的坐標(biāo)轉(zhuǎn)換
“視點(diǎn)坐標(biāo)系與一般的物體所在的世界坐標(biāo)系不同,它遵循左手法則,即左手大拇指指向Z正軸,與之垂直的四個(gè)手指指向X正軸,四指彎曲90度的方向是Y正軸。而世界坐標(biāo)系遵循右手法則的。”
4、視點(diǎn)坐標(biāo)系的透視變換公式很重要??!王飛著計(jì)算機(jī)圖形學(xué)書(shū)65頁(yè)
5、z'值的確切含義:指的是在完全作完透視投影變換之前,僅作透視投影之后的一條線
三、兩點(diǎn)透視的變換矩陣:
王飛編著《計(jì)算機(jī)圖形學(xué)基礎(chǔ)》的道理是:
從平面圖形的平移、旋轉(zhuǎn)、錯(cuò)切開(kāi)始推導(dǎo),兩點(diǎn)透視的變換矩陣可以看成是:
物體本身有一個(gè)物體坐標(biāo)系——xw,yw,zw,視點(diǎn)作為原點(diǎn)又構(gòu)成一個(gè)視點(diǎn)坐標(biāo)系——xe,ye,ze,物體坐標(biāo)系z軸朝上,y軸朝向遠(yuǎn)處;而視點(diǎn)坐標(biāo)系y軸朝上,z軸朝向遠(yuǎn)處。
這樣,最終的二點(diǎn)透視狀態(tài)可以這樣取得,首先把物體的位置的物體坐標(biāo)系表示法轉(zhuǎn)化為視點(diǎn)坐標(biāo)系的表示法(第一個(gè)矩陣),然后圍繞視點(diǎn)坐標(biāo)系的y軸旋轉(zhuǎn)(第二個(gè)矩陣),然后在x,y,z方向上平移(第三個(gè)矩陣),最后做透視變換(第四個(gè)矩陣),它的原文是把平移放在第二步,我在平移之前轉(zhuǎn)動(dòng),目的是保證了物體旋轉(zhuǎn)的軸在離它不遠(yuǎn)的地方:
我使用的矩陣變換如下,原文是是把平移放在第二步:
[xw,yw,zw,1]*
*
*
*
最后所得結(jié)果是一個(gè)新的矩陣,
[xe ye ze 1]=[cos
*xw-sin
*yw+l zw+m 2sin
*xw+2cos
*yw+2n-d (sin
*xw+cos
*yw+n)/d]
把最后一項(xiàng)變成1,可得
=[(cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n (zw+m)*d/(sin
*xw+cos
*yw+n) (2sin
*xw+2cos
*yw+2n-d)*d/(sin
*xw+cos
*yw+n) 1 ]
即:
Xe= (cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n)
Ye=(zw+m)*d/(sin
*xw+cos
*yw+n)
Ze=(2sin
*xw+2cos
*yw+2*n-d)*d/(sin
*xw+cos
*yw+n)
實(shí)際上我的delphi程序里面是這樣的:
xe:=trunc((cos(angle)*eee[ii][k].X-sin(angle)*eee[ii][k].Y+l)*d/(sin(angle)*eee[ii][k].X+cos(angle)*eee[ii][k].Y+n));
ye:=trunc((hhh[ii][k]+m)*d/(sin(angle)*eee[ii][k].X+cos(angle)*eee[ii][k].Y+n)); //透視變換
//ze可以考慮使用作為消隱
Ze:=trunc((2*sin(angle)*xw+2*cos(angle)*yw+2*n-d)*d/(sin(angle)*xw+cos(angle)*yw+n));
四、通過(guò)變換過(guò)的兩點(diǎn)透視的結(jié)果xe,ye,zw和
*,反求原來(lái)的物體坐標(biāo)xw,yw
即:xe,ye,zw和
已知,求出xw,yw
根據(jù):
Xe= (cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n) (1)
Ye=(zw+m)*d/(sin
*xw+cos
*yw+n) (2)
Ze=(2sin
*xw+2cos
*yw+2n-d)*d/(sin
*xw+cos
*yw+n) (3)
(1)除以(2)得
Xe/Ye= (cos
*xw-sin
*yw+l)/ (zw+m)
(Xe*(zw+m))/Ye=cos
*xw-sin
*yw+l
(Xe*(zw+m))/(Ye* cos
)=xw-tan
*yw+l/cos
Xw=(Xe*(zw+m))/ (Ye* cos
) - (ye*l)/(Ye* cos
)+( sin
*yw*ye)/ (Ye* cos
)
Xw=(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
) (4)
由(2)得
Ye*(sin
*xw+cos
*yw+n)= (zw+m)*d
Ye*(sin
*xw)+ye* cos
*yw+n*ye=(zw+m)*d
把(4)代入上式得
Ye* sin
*(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
)+ye* cos
*yw+n*ye=(zw+m)*d
約去ye,得
sin
*(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ cos
+ye* cos
*yw+n*ye=(zw+m)*d
tan
*(Xe*zw+xe*m+ sin
*yw*ye- ye*l) +ye* cos
*yw+n*ye=(zw+m)*d
tan
*Xe*zw+xe*m *tan
- ye*l*tan
+ sin
*tan
*yw*ye+ye* cos
*yw+n*ye=(zw+m)*d
(sin
*tan
*ye+ye* cos
)*yw+ tan
*Xe*zw+xe*m *tan
- ye*l*tan
+n*ye=(zw+m)*d
最后得
Yw=[(zw+m)*d- tan
*Xe*zw- xe*m *tan
+ ye*l*tan
- n*ye]/ (sin
*tan
*ye+ye* cos
) (5)
而前面已經(jīng)得到
Xw=(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
) (4)
實(shí)際上相當(dāng)于opengl里面的逆變換,從鼠標(biāo)選中的屏幕位置來(lái)確定對(duì)應(yīng)的三維空間中位置,opengl使用gluUnProject和gluUnProject4來(lái)計(jì)算。