從零開始實現3D軟光柵渲染器 (4) 三維空間變換

世界是3D的,顯示器是2D,將三維空間的物體變換到二維空間,再到最終屏幕上成像的過程,在圖形學中叫做3D渲染流水線。這個過程着實有點複雜了,讓我們慢慢來,本節我們先介紹一些基本的空間變換知識。

這部分知識點非常重要,不管以後做遊戲、仿真項目,還是其他圖形應用,物體的空間變換是必須要理解的,因爲很多實際的需求需要你自己分析,再去實現。就Unity來說吧,它已經把圖形學中的矩陣、向量運算封裝的相當易用了,但是如果你不明白它是怎麼玩的話,你自己的需求還是很難實現。很多人說Unity上手快,易學,確實,拖拖拽拽,加個腳本組件就能控制遊戲對象,但是要想玩得好,就必須要理解相關的圖形學背後的原理。雖然你不用真的把Unity封裝的那些高數實現一邊,但是你要懂,一個函數調用了它會發生什麼。

好了,進入今天的主題。

我們先以2D空間爲例,推導空間變換的矩陣表示,3D空間的推理是一樣的,照葫蘆畫瓢就行,後面我們給出3D空間的變換的矩陣表示。

什麼是矩陣

我們就把它看成一堆神奇的有規律的數即可,不用想的太複雜,它就是個工具。我們不是搞科研,那是數學家的事兒,我們只是應用矩陣這個工具,來解決圖形學的問題。我們沒必要對矩陣研究非常深入,我們只需要理解它如何在圖形學中的應用即可。就像你會開車,不會修車,但這並不會影響你漂移。

記得線性代數書上引入矩陣給了這麼個例子:

這個初中就學過了吧 – 二元一次方程。

這倆方程還能寫成:

對,這就是矩陣乘法。

一個2x2(兩行兩列)的矩陣 乘以 一個2x1的矩陣,得到一個2x1的矩陣。

可以看出:一個 n x n 的矩陣 和 一個 n x m 的矩陣相乘,等於一個 n x m 的矩陣。

問題1

那麼,請問:n x n 的矩陣 和 m x n 的矩陣相乘,等於多少。

答案:不能相乘。不相信你乘給我看看。

好了。現在已經學會了矩陣乘法了。你看,矩陣也不是很難嘛。

問題2

矩陣和向量(或者說點)相乘怎麼計算?

其實點和向量在表示上是沒有區別的(x,y),矩陣是工具,它不會因爲你是點不是向量而改變運算規則,對於運算的結果,在於人爲的解讀。舉個例子,你炒菜加糖還是加鹽,鍋是不會拒絕的,但是對於炒出來的菜,你是要負責任的。我想,你應該懂我意思了吧。

這其實不算問題,上面的就是矩陣和向量相乘呀。

如果有人告訴你(x,y)是個向量,那就默認爲它是從原點到點(x,y)位置的一個向量。總不能上面把它豎着寫,你就不認識了吧。

那個T叫做轉置符號,就是橫着寫和豎着寫的區別。向量還是原來的向量,只是後來有錢了,走路都橫着走了,但還是原來那個向量。

現在我們知道,向量其實也可以看作是一種特殊的矩陣。

問題3

此時,你可能會問,爲什麼要轉置啊,不轉置不行嘛?

行!當然行。

在我看來,轉不轉置都一樣。都是形式而已。中國人這還用問?

不轉置的話,上面的矩陣,就得這麼寫:

1x2 的矩陣 乘以 2x2 的矩陣,得到 1x2 的矩陣。 沒毛病。

我們始終要記住,我們最終關心的是最後得到的操作數,怎麼解釋它是人乾的事,或者說你乾的事,和你橫着寫豎着寫有關係嘛?只要你遵循對應的運算法則就是咯。你不要問爲啥要有轉置,存在即合理,就像學校查衛生時,垃圾桶不準放垃圾一樣,誰知道那些人咋想的。

問題4

我想看看兩個“真”矩陣相乘。

其實,你仔細品下,你自己也能寫出來。

下面,我們來看看矩陣是如何表示變換的。

常見的變換就是:平移、旋轉、縮放。像其他錯切變換、對稱變換啥的,哎,怎麼說呢,你平時應該用到不到,用到了再學吧。道理都是相通的嘛,學會了基本的,其他的照葫蘆畫瓢唄。

平移變換

話說,空間中某個物體,算了,來張我的照片吧。

把我的照片從一個地方挪到另一個地方,需要幾步?咳咳,你先別管爲什麼移我的照片。

很簡單,數學上,就是把每個點都平移一下。

假設(x,y)爲圖像上某一點,移動另一個位置(x’,y’),假設就位移了(a,b)吧,意思就是x方向位移了a,y方向位移了b。

那麼有:

x' = x + a
y' = y + b

好了。現在你看能不能寫成矩陣的形式。

是不是寫不出來啊~~~

先放一放啊,我們後面再說。

旋轉變換

現在把我的照片轉一轉。算了,換張你們喜歡看的吧。

現在我們規定逆時針旋轉爲正。你要規定順時針旋轉爲正。也行。前面都說了,關鍵看人(你)怎麼解釋。

我們現在取圖像上任一點A(x,y),旋轉beta角度之後,到達A’

A點原本與X軸的夾角爲alpha,爲了方便,設: |OA|=|OA’|=r

則我們可以列出以下方程:

整理下:

現在,你把這個寫成矩陣乘法的形式看看。

是不是很簡單。

縮放變換

這個很簡單。

A(x,y) 放大 Sx 和 Sy倍,得到 A’(x’, y’)

x' = x * Sx
y' = y * Sy

寫成矩陣的形式:

齊次座標

好了。基本變換到此結束。

此時,你是不是發現,除了平移變換,旋轉和縮放變換都能寫成矩陣的形式。別人有的,它當然也想要啊。

所以,引入了齊次座標。

不知道誰起的這個名字,想象力豐富的我,打死我也想不出來它乾的事和它的名字有啥關係。

簡單說,就是給向量或者矩陣多加一個維度,方便將基本的變換(平移、旋轉、縮放)都可以用矩陣乘法的形式表示。

其實,我們知道,就是爲了照顧平移變換。

座標變換的齊次座標表示

那麼如何表示呢?

我們先將之前的三個變換用齊次座標表示的矩陣形式寫出來:

平移變換:

旋轉變換:

縮放變換:

大家快速驗算一下,應該都成立吧。

通過觀察可知,我們將點(x,y) 變成了齊次座標(x,y,1).

有時候給你一個(x,y),你知道它是點還是向量?因爲大家都知道,向量的代數表示和點是一樣的。

這個時候就是齊次座標的第二個妙用。

點(x,y) 寫成齊次座標是: (x,y,1)

向量(x,y) 寫成齊次座標是: (x,y,0)

爲啥?

我也不知道爲啥,我就覺得這麼幹是對的,而且很神奇。

咱們來驗算一下:點是有位置的,向量是沒有位置的,是吧。

那咱們用平移矩陣來驗算一下不就好了嘛。

數學是不是很奇妙。

那這個有啥用呢?

後面推導3D渲染流水線的投影變換階段好像用到,到時候再說吧。

其實,一個點或者向量的齊次表示不是唯一的,點(x,y)可以表示成(kx,ky,k),向量(x,y)可以表示成(kx,ky,0). 這個不難理解吧。

三維空間變換

三維空間變換矩陣的推導和二維空間很相似,只不過多了一個維度嘛。

三維座標系,有2種,左手座標系和右手座標系,區別就在於Z軸的朝向不同。爲啥有2種。額,我想這個和人有左撇子和右撇子道理應該差不多吧。

那麼,我們用那種呢?前面已經說了,隨便你,只要你選定一種座標系,數學推導的過程是完全一樣的。我們這裏推導使用的是右手座標系,因爲我是右撇子。

平移矩陣,幾乎和二維變化一樣:

旋轉矩陣,二維空間繞的是原點,三維空間繞的是座標軸。

繞z軸旋轉某個角度的旋轉矩陣:

大家是不是有點眼熟?對嗎,這不就是二維旋轉矩陣加了一個維度嘛。大家想想,繞z軸旋轉,是不是在XY平面內?那是不是就是二維旋轉?這不就得了,那繞x軸和繞y軸旋轉,不就是一樣的道理嘛?

繞x軸旋轉某角度:

繞y軸旋轉某角度:

有個事情要注意下啊,我們這裏推導的變換矩陣和你們在其他地方看到的可能不一樣,彆着急。你轉置一下看看是不是就一樣的了。這是最後一遍嘮叨了啊,轉不轉置,你自己看着辦,你喜歡用哪種就用哪種,關鍵要用對場合。我的建議是,根據你以後學習的圖形編程API來決定使用那種風格的矩陣、座標系。比如說,OpenGL,使用的是右手座標系,使用的是向量右乘(矩陣x向量, 而不是向量x矩陣,前者是列向量,就是豎着寫的那個,後者是橫向量,即使橫着寫的那個)。所以,我就是按着這個推導的,並不是因爲我是右撇子。

本節介紹的基本變換,經過組合,可以形成複雜的變換。

怎麼組合?

多個變換矩陣相乘呀,注意,相乘的順序喲。這個現在你是感受不到的,只有你實戰的時候,你才能發現區別。

好了,本節的內容到此就結束了。

小夥伴們有什麼建議,可以留言。我也不知道是不是講得太細,或者講得太粗,就按照自己的想法來。大家有什麼建議可以說出來。或者如果大家有感興趣的話題,也可以說出來。只要我會的,我也會寫相關的教程。其實,我也不是科班出身,只是興趣使然,歡迎小夥伴一起探討學習。

歡迎大家關注我的公衆號【OpenGL編程】,定期分享OpenGL相關的3D編程教程、算法、小項目。歡迎大家一起交流。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章