參考課程P4:
https://www.bilibili.com/video/BV1X7411F744?p=4
注:關于這部分知識,可以參考馮樂樂 Unity Shader入門精要的4.6節,會有實例講述MVP的全過程,我也會在后續筆記中做記錄。
我們可以這樣來描述視圖變換的任務:將虛擬世界中以(x,y,z)為坐標的物體變換到 以一個個像素位置(x,y) 來表示的屏幕坐標系之中(2維),這確實是一個較為復雜的過程,但是整個過程可以被細分為如下幾個步驟:
- 模型變換(modeling tranformation):這一步的目的是將虛擬世界中或者更具體點,游戲場景中的物體調整至他們應該在的位置
- 攝像機變換(view/camera tranformation):在游戲中我們真正在乎的是攝像機(或者說眼睛)所看到的東西,也就是需要得到物體與攝像機的相對位置
- 投影變換(projection tranformation):根據攝像機變換得到了所有可視范圍內的物體對于攝像機的相對位置坐標(x,y,z)之后,便是根據是平行投影還是透視投影,將三維空間投影至標準二維平面([-1,1]^2)之上 (tips:這里的z并沒有丟掉,為了之后的遮擋關系檢測)
- 視口變換(viewport transformation):將處于標準平面映射到屏幕分辨率范圍之內,即[-1,1]^2 ->[0,width]*[0,height], 其中width和height指屏幕分辨率大小
M在前面的坐標變換中已經說了,現在重點看view/camera tranformation。
一、view/camera tranformation
1.相機的定義
- 相機的位置 e
- 相機看向的方向 g
- 相機向上的方向 t
2.相機位置
上面的截圖說的是,考慮到運動的相對性,如果相機和物體一起移動,那么拍出來的照片是相同的。沿著這種思路,把相機放在世界坐標的原點,并讓坐標軸與世界空間重合,然后再讓物體移動,就能達到同樣的效果。
這里也介紹一下正常的思路,根據基變換的思路。要得到世界坐標的物體在相機空間的坐標,可以把世界坐標的基轉換到相機空間。以Unity舉例,我們更容易獲得的是攝像機在世界空間中的坐標,所以需要對這個變換進行求逆,才能得到我們的目標矩陣。
這兩種思路,最終選擇的是把相機移到原點的思路。視頻中說到這樣做的好處:會讓操作得到簡化
3.移動相機的具體步驟
因為相機到達目前的位置,是先進行了縮放、旋轉,再平移?,F在為了恢復到原點,就是逆過來操作,需要先做逆平移,再做逆旋轉。如下圖:
相機旋轉到世界坐標軸的矩陣是很難寫的,但是反過來世界坐標軸旋轉到相機當前的基坐標卻很簡單,即從x旋轉到g叉乘t(也就是e),y旋轉到t,z旋轉到-g非常簡單,如圖:
然后再去求這個變換的逆,就是我們想要的目標了。而旋轉矩陣是一個正交矩陣,直接轉置即可得到最終答案:
上面的公式只是講述了原理,具體例可以參考馮樂樂 Unity Shader入門精要的4.6節。
二、projection
1.正交投影 orthographic
把左側的立方體,映射到中心的標準立方體。這樣做是為了什么呢?大佬沒有講,有彈幕說是為了裁剪。
其中,l,r,b,t,f,n對應的是left,right,bottom,top,far,near。因為我們現在右手坐標系,相機是向-Z方向看,所以離我們遠的物體,它的Z值是更小的。這樣就有點反直覺,因為感覺上,值越大,應該是離得越遠。如果是左手坐標系,就不會有這個問題。
操作步驟很簡單,先平移,再縮放:
平移的數值是在求中點,正負號可以忽略,圖中這個位置才是負的。然后縮放是因為要放到一個-1到1,即長度為2的正方體里,縮放倍數就是r-l/(2/r-l)=2
有人提問,這樣處理之后,正方體就被拉伸了呀,答案是所有物體放到-1,1的立方體后,后續還會做視口變換。
2.透視投影 prerspective
把那個遠平面擠壓成和近平面一樣大,再做一個正交投影就達到目的了。擠的要求:
- 近平面不變
- 遠平面在收縮時,Z軸的值不能變,即f值不能變
- 遠平面的中心點不能變
為了做這個擠壓操作,可以切開來看:
這里利用相似三角形即可,然后齊次坐標,是可以同時擴大z倍的,就得到如下結果:
這里z為什么是unknown呢,彈幕里有人表示,兩個平面的z確實沒變,但中間的那些點都是不一樣的。
現在已經能得到這個矩陣的一部分數值了。剩下的事情就是算出問號部分的?,F在已知:
近平面的Z是不變的,即x,y,n,1。這里利用齊次坐標的性質變成這樣:
現在思路一下,什么樣的矩陣左乘x,y,n,1。能在第三行出現一個n^2呢,那必然是一個前兩個格子都是0的矩陣,這樣才能把x,y都消掉:
這里可能不好理解,為什么要構造一個n^2,其實是類似高中時那種特殊值求函數的思路,也可以叫特殊系數法。
現在還一個條件,即遠平面的中心點0,0,f,1映射完之后還是0,0,f,1。這里利用齊次坐標的性質變成這樣:
所以根據遠平面就可以得到Af+B=f^2
然后結合上面根據近平面得到的結論:
兩個式子聯合:
現在可以完成最后一步了: