前提
Games101 lecture4-lecture5
考慮將三位物體轉換二維圖像需要的步驟,我們需要以下變換來達成目的,
model transformation(模型(基礎)變換–Object就位)
view/camera transformation(視圖變換–調整相機)
projection transformation(投影變換–變換到[−1,1]3,忽略深度信息z,變成[−1,1]2)
viewport transformation(視口變換–投影到屏幕空間)
如下圖所示(Fundamentals of Computer Graphics (3rd Edition) 7.1 Viewing Transformations Figure 7.2):
視圖變換
首先需要定義一個相機,一個相機有三個屬性,位置(Positon)eee,觀測方向(Look-at/ gaze direction)ggg和向上方向(Up direction)ttt。
同時只要相機和物體之間沒有相對運動,觀測結果就不會改變,則可以讓相機固定在原點,向上方向爲Y方向,看向−Z方向,而這就需要通過變換矩陣Mview來自達成(需要注意的是物體也會隨着相機移動而移動,因爲要保證兩者之間沒有相對運動),該矩陣需要完成如下操作:
- 將原來在任意點eee的相機平移到原點
- 將觀測方向ggg旋轉到−Z方向
- 將向上方向ttt旋轉到Y方向
- 將{gggXttt}方向旋轉到X方向(當前兩個方向旋轉完成之後,X方向自然對齊)
如下圖所示:
Mview先平移在旋轉(和仿射變換不同),即Mview=RviewTview。
最後結果如下:
Mview=RviewTview=⎣⎢⎢⎡xgXtxtx−g0ygXtyty−g0zgXtztz−g00001⎦⎥⎥⎤⎣⎢⎢⎡100001000010−xe−ye−ze1⎦⎥⎥⎤
推導過程
首先是平移到原點,可以很自然的寫出其平移矩陣Tview如下:
Tview=⎣⎢⎢⎡100001000010−xe−ye−ze1⎦⎥⎥⎤
接着考慮旋轉,將任意方向旋轉到X,Y,−Z方向上不容易寫出,但是可以考慮其逆變換,寫出將X(1,0,0),Y(0,1,0),Z(0,0,1)旋轉到{gggXttt},ttt,−g−g−g的旋轉矩陣Rview−1,並且由於旋轉矩陣是正交矩陣,所以只要寫出Rview−1,其轉置矩陣即爲所求,如下所示:
Rview−1=⎣⎢⎢⎡xgXtygXtzgXt0xtytzt0x−gy−gz−g00001⎦⎥⎥⎤
可以通過將上述矩陣應用與三軸來檢驗其正確性。Rview如下所示:
Rview=Rview(−1)(−1)=RviewT=⎣⎢⎢⎡xgXtxtx−g0ygXtyty−g0zgXtztz−g00001⎦⎥⎥⎤
所以最終的Mview如開頭所示。
投影變換
投影變換目的就是將物體變換到[−1,1]3。想要得到二維圖像,可以去掉z,變成[−1,1]2。變換分爲兩種,正交(orthographic)投影和透視(prespective)投影。透視投影存在近大遠小的現象,而正交投影則不會,這是兩者的本質區別,兩者分別如下圖所示:
圖片來源:https://stackoverflow.com/questions/36573283/from-perspective-picture-to-orthographic-picture
上圖中透視投影圍成一個視錐(四棱錐),而視錐中從某一個深度到另一個深度之間的區域叫做frustum,而透視投影就是將frustum中的東西顯示到近平面(Near clip plane)上。
正交投影(右手系)
首先定義一個空間中的立方體(只需定義6個面,左右上下前後),[l,r]x[b,t]x[f,n],需要注意的是遠平面(f)和近平面(n),有nnn>fff因爲看向−Z(右手系),所以物體越遠則其對應的Z的值越小,反之越大。如果是左手系則越遠Z越大,因爲看向的+Z方向。然後將立方體中心平移到原點,並將其縮放成canonical(正則規範標準立方體) cube[−1,1]3,忽略z,則變爲[−1,1]2。
如下圖所示:
先將立方體中心(2r+l,2t+b,2n+f)平移到原點,然後縮放到[−1,1]3(長寬高爲2),這裏的縮放其實就是將立方體的長寬高縮放爲2,其變換矩陣Mortho如下:
Mortho=⎣⎢⎢⎡r−l20000t−b20000n−f200001⎦⎥⎥⎤⎣⎢⎢⎡100001000010−2r+l−2t+b−2n+f1⎦⎥⎥⎤=⎣⎢⎢⎡r−l20000t−b20000n−f20−r−lr+l−t−bt+b−n−fn+f1⎦⎥⎥⎤
透視投影
視錐定義
透視投影的視錐定義只要定義兩個東西1.垂直可視角度$Y2.寬高比aspect$,如下圖所示:
從側面觀察,則近平面距離相機距離爲∣n∣,如下圖所示:
怎麼做透視投影Mpersp=MorthoMpersp−>ortho
- 首先將frustum擠壓成一個長方體(Mpersp−>ortho)([l,r]x[b,t]x[f,n],);
- 然後再做一次正交投影(Mortho,已知)。即可完成投影到近平面的任務。
如下圖所示:
前提規定
-
在擠壓過程(第一步)中frustum的近平面n上點不變;
-
f平面的Z值不變,因爲只是在收縮;
-
f平面的中心點是不會改變的(擠壓完還是中心點)。
推導過程
先單獨考慮擠壓過程,我們需要找到一個矩陣來完成變換。
考慮下圖,從視錐的側面看,我們需要將(x,y,z)擠壓到和近平面上點(x′,y′,z′)一樣的高度,考慮相似三角形,則有y′=zny;同理(從上面看),對於x而言有x′=znx。
需要注意的是,這裏nnn,zzz在圖上表示的是距離原點的距離(負Z方向),所以是個負數。
至此,已知擠壓過程x,y的變換,z未知,將上述變換用齊次座標,同時在基礎變換中我們提到過對於齊次座標而言,(x,y,z,w)T(w!=0)表示的點即爲(wx,wy,wz,1)T。 所以有如下關係:
Mpersp−>ortho⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡znxzny?1⎦⎥⎥⎤=同乘z⎣⎢⎢⎡nxny?z⎦⎥⎥⎤
從中可以反推出Mpersp−>ortho如下:
Mpersp−>ortho=⎣⎢⎢⎡n0?00n?000?100?0⎦⎥⎥⎤
同時因爲擠壓過程中近平面點不變,遠平面點Z值不變。則對於一個近平面上點(x,y,n,1)T(假設近平面上的z的值爲n)。考慮齊次座標中一個點可以有很多不同的表示,同理則有(x,y,n,1)T=同乘n(nx,ny,n2,n)T變換後是不變的。所以有如下關係:
Mpersp−>ortho⎣⎢⎢⎡xyn1⎦⎥⎥⎤=⎣⎢⎢⎡nxny?z⎦⎥⎥⎤=⎣⎢⎢⎡nxnyn2n⎦⎥⎥⎤
則可以推出變換矩陣的第三行爲(0,0,A,B),即有式子(1)如下:
[00AB]⎣⎢⎢⎡xyn1⎦⎥⎥⎤=n2(1)
再考慮f平面中z不變,且中心點不變,則對於其中心點(0,0,f,1)(假設遠平面上z值爲f)。則有如下關係式子(2):
⎣⎢⎢⎡00f1⎦⎥⎥⎤=同乘f⎣⎢⎢⎡00f2f⎦⎥⎥⎤⇒[00AB]⎣⎢⎢⎡00f1⎦⎥⎥⎤=⎣⎢⎢⎡00f2f⎦⎥⎥⎤(2)
由(1)(2)可得,如下結果
{An+B=n2Af+B=f2⇒{A=n+fB=−nf
則有
Mpersp−>ortho=⎣⎢⎢⎡n0000n0000n+f100−nf0⎦⎥⎥⎤
所以透視投影變換矩陣計算如下:
Mpersp=MorthoMpersp−>ortho=⎣⎢⎢⎡r−l2n0000t−b2n00−r−lr+l−t−bt+bn−fn+f100−n−f2nf0⎦⎥⎥⎤
Question:frustum中間的點的變化
在frustum中間任何一個位置,比如點(x,y,2n+f,1)T,經過擠壓之後(不做第二步正交)更加靠近遠平面還是近平面?(遠平面)
推導過程
先將Mpersp−>ortho應用到該點上,如下:
Mpersp−>ortho⎣⎢⎢⎡xy2n+f1⎦⎥⎥⎤=⎣⎢⎢⎡nxny2(n+f)2−nf2n+f⎦⎥⎥⎤=規範化,同除以2n+f⎣⎢⎢⎢⎡n+f2nxn+f2nyn+f−n+f2nf1⎦⎥⎥⎥⎤
比較變換前後兩點的Z值大小,如下:
n+f−n+f2nf−2n+f=2n+f−n+f2nf=2(n+f)(n+f)2−4nf=2(n+f)(n−f)2
前面提到此時的n,f是個負數,所以有(n−f)2>0,(n+f)<0,即更加靠近遠平面。