0x00 前言
首先要說(shuō)明的是迈嘹,本文的標(biāo)題事實(shí)上來(lái)自于知乎上的一個(gè)同名問(wèn)題:為什么directX里表示三維坐標(biāo)要建一個(gè)4*4的矩陣鸟蟹? - 編程(https://www.zhihu.com/question/36296104) 。因此森书,正如Milo Yip大神所說(shuō)的這個(gè)標(biāo)題事實(shí)上是存在問(wèn)題的:矩陣是用于表示變換而不是坐標(biāo)的靶端。再了解了矩陣的作用之后,我們就要繼續(xù)思考為什么變換要使用一個(gè)4×4的矩陣而不是3×3的矩陣呢凛膏?是不是多此一舉呢杨名?下面我們就來(lái)聊聊這個(gè)話題。
0x01 怎么平移一個(gè)三維空間中的點(diǎn)猖毫?
我們應(yīng)該怎么平移一個(gè)三維空間中的點(diǎn)呢镣煮?答案很簡(jiǎn)單,我們只需要對(duì)這個(gè)點(diǎn)的坐標(biāo)中的每個(gè)分量(x,y,z)和對(duì)應(yīng)軸上的平移距離相加即可鄙麦。
例如典唇,點(diǎn)p1(x1,y1,z1)在X軸Y軸以及Z軸上分別平移Δx,Δy,Δz到新的點(diǎn)p2(x2,y2,z2)镊折,那么我們只需在坐標(biāo)對(duì)應(yīng)的分量上加上這些增量就可以確定點(diǎn)p2的坐標(biāo)了。
x2 = x1 + Δx
y2 = y1 + Δy
z2 = z1 + Δz
很簡(jiǎn)單是嗎介衔?那么接下來(lái)再讓我們來(lái)看一看另一種變換:旋轉(zhuǎn)恨胚。
0x02 再來(lái)旋轉(zhuǎn)一個(gè)點(diǎn)
旋轉(zhuǎn)相比較平移來(lái)說(shuō),會(huì)略顯復(fù)雜一些炎咖。因?yàn)槲覀冃枰该饕韵聨讉€(gè)方面來(lái)描述一個(gè)旋轉(zhuǎn):
旋轉(zhuǎn)軸
旋轉(zhuǎn)方向
旋轉(zhuǎn)角度
在這里赃泡,我們假設(shè)點(diǎn)p需要繞Z軸順時(shí)針旋轉(zhuǎn)β度。
如這個(gè)很難看的圖所示乘盼,我們的點(diǎn)P1(x1,y1,z1)以Z軸位軸順時(shí)針旋轉(zhuǎn)β度之后來(lái)到了點(diǎn)P2(x2,y2,z2)升熊。接下來(lái),讓我們假設(shè)原點(diǎn)到P1的距離位L绸栅,且P1和Y軸之間的夾角位α级野,那么根據(jù)三角函數(shù)公式我們就可以計(jì)算出P1點(diǎn)的具體坐標(biāo)了:
x1 = L·sinα
y1 = L·cosα
由于是繞Z軸旋轉(zhuǎn),因此z坐標(biāo)不變粹胯,因此此處不考慮蓖柔。
同樣根據(jù)三角函數(shù)公式,我們可以繼續(xù)計(jì)算出P2的具體坐標(biāo):
x2 = L·sin(α + β)
y2 = L·cos(α + β)
再讓我們回憶一下中學(xué)時(shí)代的幾何數(shù)學(xué)的內(nèi)容风纠,對(duì)青春的回憶又把我們帶回了課堂上老師聲嘶力竭向我們傳授的內(nèi)容——兩角和與差:
cos(α+β)=cosα·cosβ-sinα·sinβ
cos(α-β)=cosα·cosβ+sinα·sinβ
sin(α+β)=sinα·cosβ+cosα·sinβ
sin(α-β)=sinα·cosβ-cosα·sinβ
回憶起老師傳授給我們的知識(shí)之后况鸣,接下來(lái)結(jié)合P1的坐標(biāo)表示形式我們就可以把P2的坐標(biāo)換一個(gè)表示形式了。
x2 = L·(sinα·cosβ+cosα·sinβ) = cosβ·x1 + sinβ·y1
y2 = L·(cosα·cosβ-sinα·sinβ) = cosβ·y1 - sinβ·x1
z2 = z1
因此竹观,在已知P1點(diǎn)坐標(biāo)以及旋轉(zhuǎn)角度β的情況下镐捧,我們就可以根據(jù)以上公式分別求出P2點(diǎn)坐標(biāo)的各個(gè)分量。如果再結(jié)合上一小節(jié)中平移一個(gè)點(diǎn)的公式來(lái)看臭增,我們可以發(fā)現(xiàn)似乎并不需要矩陣愤估,而僅僅通過(guò)兩組表達(dá)式就能實(shí)現(xiàn)坐標(biāo)的變換。但是......
0x03 帶來(lái)便捷的矩陣
當(dāng)然速址,從理論上講我們的確可以只通過(guò)數(shù)學(xué)公式就能實(shí)現(xiàn)變換,但實(shí)際的情況卻是在變換十分復(fù)雜時(shí)由驹,直接使用數(shù)學(xué)表達(dá)式來(lái)進(jìn)行運(yùn)算也是相當(dāng)繁復(fù)的芍锚。因此,在現(xiàn)實(shí)中常常使用矩陣(由m × n個(gè)標(biāo)量組成的長(zhǎng)方形數(shù)組)來(lái)表示諸如平移蔓榄、旋轉(zhuǎn)以及縮放等線性變換并炮。而兩個(gè)變換矩陣A和B的積P=AB,則變換矩陣P相當(dāng)于A和B所代表的變換甥郑。舉一個(gè)例子逃魄,若A為旋轉(zhuǎn)矩陣,B為平移矩陣澜搅,則矩陣P就能夠?qū)崿F(xiàn)旋轉(zhuǎn)和平移變換伍俘。不過(guò)需要注意的是邪锌,矩陣乘法不符合交換律,因此AB和BA并不相等癌瘾。
說(shuō)了這么多觅丰,我們似乎還是沒(méi)有回答為什么三維空間需要一個(gè)4×4矩陣來(lái)實(shí)現(xiàn)變換呢?下面我們就帶著這個(gè)問(wèn)題妨退,分別看看3×3矩陣和4×4矩陣的使用吧妇萄。
3×3矩陣和旋轉(zhuǎn)
首先,我們先來(lái)看一個(gè)矩陣乘以一個(gè)三維矢量的算式:
可以看到該矩陣為一個(gè)3×3的矩陣咬荷,矩陣的右側(cè)是點(diǎn)P1的坐標(biāo)冠句,而矩陣的左側(cè)則是點(diǎn)P2的坐標(biāo)。根據(jù)這個(gè)表達(dá)式幸乒,我們可以求出x2懦底、y2、z2的值:
x2 = a·x1 + b·y1 + c·z1
y2 = d·x1 + e·y1 + f·z1
z2 = g·x1 + h·y1 + i·z1
為了將矩陣等式和之前小節(jié)的數(shù)學(xué)表達(dá)式聯(lián)系起來(lái)逝变,下面我們就將旋轉(zhuǎn)表達(dá)式和該矩陣等式做一個(gè)對(duì)比基茵。
x2 = a·x1 + b·y1 + c·z1
x2 = cosβ·x1 + sinβ·y1
y2 = d·x1 + e·y1 + f·z1
y2 = cosβ·y1 - sinβ·x1
z2 = g·x1 + h·y1 + i·z1
z2 = z1
通過(guò)對(duì)比x2,我們可以發(fā)現(xiàn)a=cosβ壳影,b=sinβ拱层,c=0;
對(duì)比y2宴咧,也可以發(fā)現(xiàn)d=-sinβ根灯,e=cosβ,f=0掺栅;
最后對(duì)比z2烙肺,可以確定g=0,h=0氧卧,i=1桃笙;
將這個(gè)結(jié)果帶入到之前的矩陣中,我們的等式就可以變成下面這個(gè)樣子:
也就是說(shuō)沙绝,通過(guò)這個(gè)3×3的變換矩陣搏明,我們就已經(jīng)實(shí)現(xiàn)了三維空間的旋轉(zhuǎn)變換。那么為什么還需要使用4×4矩陣呢闪檬?
搞不定的平移星著,4×4矩陣來(lái)救場(chǎng)
我們已經(jīng)通過(guò)一個(gè)3×3矩陣搞定了旋轉(zhuǎn)變換,顯然如果這個(gè)3×3矩陣真的是完美的解決變換的方案的話粗悯,那么它顯然也必須要適合于其他的變換虚循,例如平移。但是它到底能否滿足平移的需求呢?下面我們還是通過(guò)對(duì)比矩陣等式和數(shù)學(xué)表達(dá)式的方式横缔,來(lái)尋找答案铺遂。
x2 = a·x1 + b·y1 + c·z1
x2 = x1 + Δx
y2 = d·x1 + e·y1 + f·z1
y2 = y1 + Δy
z2 = g·x1 + h·y1 + i·z1
z2 = z1 + Δz
通過(guò)對(duì)比,我們發(fā)現(xiàn)平移和旋轉(zhuǎn)之間很有趣的一個(gè)區(qū)別剪廉,那就是平移的表達(dá)式中帶有常量Δx娃循,而無(wú)論是旋轉(zhuǎn)的表達(dá)式還是矩陣等式中都不存在這樣一個(gè)常量能夠與之對(duì)應(yīng)。那么問(wèn)題就來(lái)斗蒋,我們沒(méi)有辦法使用3×3的矩陣來(lái)表示平移捌斧。答案其實(shí)很簡(jiǎn)單,那就是使用4×4矩陣來(lái)實(shí)現(xiàn)泉沾。但是隨之而來(lái)的一個(gè)問(wèn)題就是如何一個(gè)三維坐標(biāo)如何能和一個(gè)4×4的矩陣相乘呢捞蚂?
齊次坐標(biāo)
為了解決三維矢量和4×4矩陣相乘的問(wèn)題,我們機(jī)智的為三維矢量添加了第四個(gè)分量跷究,這樣之前的三維矢量(x,y,z)就變成了四維的(x,y,z,w)姓迅,這樣由4個(gè)分量組成的矢量便被稱為齊次坐標(biāo)。需要說(shuō)明的是俊马,齊次坐標(biāo)(x,y,z,w)等價(jià)于三維坐標(biāo)(x/w,y/w,z/w)丁存,因此只要w分量的值是1,那么這個(gè)齊次坐標(biāo)就可以被當(dāng)作三維坐標(biāo)來(lái)使用柴我,而且所表示的坐標(biāo)就是以x解寝,y,z這3個(gè)值為坐標(biāo)值的點(diǎn)艘儒。
因此聋伦,為了和4×4矩陣相乘,我們的P1點(diǎn)坐標(biāo)就變成了(x1,y1,z1,1)界睁。而矩陣等式也變成了下面這個(gè)樣子:
我們?cè)賹⑦@個(gè)新的矩陣等式和平移的數(shù)學(xué)表達(dá)式做一番對(duì)比:
x2 = a·x1 + b·y1 + c·z1 + d
x2 = x1 + Δx
y2 = e·x1 + f·y1 + g·z1 + h
y2 = y1 + Δy
z2 = i·x1 + j·y1 + k·z1 + l
z2 = z1 + Δz
1 = m·x1 + n·y1 + o·z1 + p
通過(guò)對(duì)比x2觉增,我們可以發(fā)現(xiàn)a=1,b=0翻斟,c=0逾礁,d=Δx;
對(duì)比y2访惜,也可以發(fā)現(xiàn)e=0嘹履,f=1,g=0疾牲,h=Δy;
再對(duì)比z2衙解,可以確定i=0阳柔,j=0,k=1蚓峦,l=Δz舌剂;
最后還可以根據(jù)表達(dá)式求出m=0济锄,n=0,o=0霍转,p=1荐绝;
這樣,我們就求出了我們的4×4的平移矩陣:
0x04 總結(jié)
寫到這里避消,不知各位是否還記得之前在介紹矩陣乘法的時(shí)候我有提到過(guò)兩個(gè)變換矩陣A和B的積P=AB低滩,相當(dāng)于A和B所代表的變換。事實(shí)上在游戲編程中岩喷,常常需要把一連串的變換預(yù)先通過(guò)計(jì)算成為單一矩陣恕沫,所以就不能即存在3×3的矩陣又存在4×4的矩陣。而將3×3矩陣拓展成4×4矩陣還是相對(duì)更加容易的纱意。這樣婶溯,就通過(guò)一個(gè)4×4矩陣整合了平移矩陣、旋轉(zhuǎn)矩陣偷霉。
原文鏈接?傳送門