3D遊戲中Model、View矩陣的分析
正如把大象裝進冰箱一樣,把3D世界中的物體呈現在我們人眼所見的屏幕上也需要三步:把物體放入世界中,將攝像頭指向物體,最後把攝像頭所觀察到的事物投影到屏幕。這三個環節的執行是通過將物體的齊次坐標與不同階段所需的矩陣相乘得到的。本篇文章討論前兩個環節,通過對移動旋轉(Model)/觀察(View)矩陣的組成進行分析,來對其各部分數值的作用進行總結,最後幫助大家理解,將所涉及內容應用到物體自轉的實現和天空盒(3D世界中的天空)渲染的例子。註:本文圖形API默認使用openGL,坐標係為右手坐標系。
一.將物體放入世界中
這一步是通過與移動旋/轉矩陣相乘來完成的。移動矩陣是變換矩陣中結構最簡單最好掌握的矩陣,結構如下:
矩陣中dx,dy,dz分別負責x,y,z軸方向的移動(具體原理不做分析,請自行計算推導)。
旋轉矩陣是三個軸矩陣的乘積(也可以通過四元數來實現旋轉變換,在這裡不做討論),三個矩陣分別是圍繞x,y,z軸旋轉θ角度的矩陣:
最後的移動旋轉矩陣為上述四個矩陣的乘積,所得矩陣我們可以表示為(a至i為任意變數):
在這裡,通過矩陣乘法規則可以得出:上邊矩陣中藍色的值(dx,dy,dz)與移動矩陣中的dx,dy,dz相等,而紅色的值為三個旋轉矩陣乘積所產生的值,不受移動矩陣影響。以OpenGL為例,最後我們看一下在程序中編寫移動旋轉矩陣(Model Matrix)的代碼:
總結:物體(Entity)坐標與上述矩陣相乘後,就實現了把物體移動到世界指定位置並將其旋轉的動作。
思考:
有同學可能會問,上述旋轉矩陣只解決了圍繞三個坐標軸的旋轉,如果想讓物體進行自轉(例如籃球、飛彈等物體)該怎麼做?不要緊,通過上述知識,可以用增加矩陣的方式實現自轉,也就是先把物體中心移動到原點再與旋轉矩陣相乘,這樣圍繞著坐標軸的旋轉也就成了自轉。之後再把物體移動回所需位置。完成這一系列動作所需的矩陣可以通過將這幾步的相關矩陣相乘而得到。具體代碼如下:
二.將攝像頭指向物體
這一步是通過與觀察矩陣相乘來完成的,觀察矩陣與移動矩陣相似,都是由移動矩陣和轉動矩陣相乘所得,但每個矩陣代表的意義完全不同。首先我們來看代碼:
等等,你會發現,這個矩陣和上邊的移動旋轉(Model)矩陣幾乎一樣,只是函數取值對象從物體(Entity)變成了攝像機(Camera)。還有一個比較重要的地方,那就是下邊移動矩陣中攝像機的位置乘以了一個-1,這都說明了什麼呢?
因為這些矩陣最終與物體坐標相乘的順序是由下到上(圖3箭頭所示)我們先來討論移動矩陣。根據物體相對運動的原理,一個物體相對另一個物體向左移動,也就等價於第一個物體不動而另一個物體相對它向右移動。所以,世界中物體與這裡的移動矩陣相乘就等價於攝像頭不動,而整個世界「配合」它移動,所以才把攝像頭的位置數值乘以-1。這也就揭示了我們在3d遊戲世界中移動的本質:當你「向前走」的時候,其實是因為整個世界「向後退」才造成你有向前走的感覺的,攝像頭的位置(許多時候也就是主角的位置)並沒有變。移動矩陣後就要與攝像頭的旋轉矩陣相乘(按圖3中箭頭方向)。在這裡,世界已經「移動完畢」,就等著我們「轉動」攝像頭來觀察世界了,所以要乘以攝像頭的移動參數(Camera.rotation)矩陣。上述變換流程結束後,攝像頭「拍攝」到的物體通過乘以投影矩陣(在這裡不做討論)就可以映射到了我們的屏幕了。
總結:通過觀察矩陣,我們把物體轉移到了攝像頭面前,之後旋轉攝像頭視角,準備把視角范偉內的物體通過投影矩陣映射到屏幕。
思考:
有人可能會問:好多遊戲中的世界範圍是有限的(通常是在一個很大的一個盒子里,盒子的表面貼圖為天空以給人一種天空的感覺,簡稱「天空盒」),如圖:
如果按這種方式讓「整個世界」動作,攝像頭移出了世界豈不「穿幫」了?其實,如果按照上述矩陣進行變化的話,完全會出現這個現象:
大家可以看到,我們把攝像頭「移出」了世界,就變成這個樣子,原來整個世界都在這個「大盒子」里。要想讓遊戲不在這裡穿幫,有沒有一種方法使世界中的物體照常移動而使天空與攝像頭相對不動?這樣的話就保證無論怎樣,攝像頭都被天空盒包住,也就是在世界中。這就要結合我們之前學過的移動旋轉矩陣組成知識了,假設觀察矩陣為:
我們知道這個矩陣中dx,dy,dz負責物體的移動,要想讓天空盒相對攝像頭不動,只要在天空盒與攝像頭的觀察矩陣相乘前,將觀察矩陣dx,dy,dz位置上的數值清零即可,最後的矩陣變為:
這樣無論攝像頭怎麼動作,天空盒與其保持不動,也就給人產生了天空「無邊無際」的感覺。我們來看實現代碼:
圖中方框內的代碼是將視察矩陣中負責轉動的變數清零的操作,之後再傳入著色器。
渲染時,只有天空盒向著色器傳入的觀察矩陣被處理過,所以除了天空盒,世界所有物體正常移動。
推薦閱讀:
※一種高效的SSS模擬
※從玩具總動員到汽車總動員2
※拓幻圖形學工程師教學手冊(第三講)|一字一字敲出OpenGL學習教程
※[Addon 2017] Stylized VFX in RiME
※Substance Designer 中實現形態圖形處理演算法(II) --- 非均勻的腐蝕拓展