“為什么DirectX里表示三維坐標要建一個4*4的矩陣?”


0x00 前言


首先要說明的是,本文的標題事實上來自於知乎上的一個同名問題:為什么directX里表示三維坐標要建一個4*4的矩陣? - 編程 。因此,正如Milo Yip大神所說的這個標題事實上是存在問題的:矩陣是用於表示變換而不是坐標的。再了解了矩陣的作用之后,我們就要繼續思考為什么變換要使用一個4×4的矩陣而不是3×3的矩陣呢?是不是多此一舉呢?下面我們就來聊聊這個話題。

0x01 怎么平移一個三維空間中的點?

我們應該怎么平移一個三維空間中的點呢?答案很簡單,我們只需要對這個點的坐標中的每個分量(x,y,z)和對應軸上的平移距離相加即可。

例如,點p1(x1,y1,z1)在X軸Y軸以及Z軸上分別平移Δx,Δy,Δz到新的點p2(x2,y2,z2),那么我們只需在坐標對應的分量上加上這些增量就可以確定點p2的坐標了。
此處輸入圖片的描述

x2 = x1 + Δx

y2 = y1 + Δy

z2 = z1 + Δz

很簡單是嗎?那么接下來再讓我們來看一看另一種變換:旋轉。

0x02 再來旋轉一個點

旋轉相比較平移來說,會略顯復雜一些。因為我們需要指明以下幾個方面來描述一個旋轉:

  1. 旋轉軸
  2. 旋轉方向
  3. 旋轉角度

在這里,我們假設點p需要繞Z軸順時針旋轉β度。
此處輸入圖片的描述
如這個很難看的圖所示,我們的點P1(x1,y1,z1)以Z軸位軸順時針旋轉β度之后來到了點P2(x2,y2,z2)。接下來,讓我們假設原點到P1的距離位L,且P1和Y軸之間的夾角位α,那么根據三角函數公式我們就可以計算出P1點的具體坐標了:

x1 = L·sinα

y1 = L·cosα

由於是繞Z軸旋轉,因此z坐標不變,因此此處不考慮。

同樣根據三角函數公式,我們可以繼續計算出P2的具體坐標:

x2 = L·sin(α + β)

y2 = L·cos(α + β)

再讓我們回憶一下中學時代的幾何數學的內容,對青春的回憶又把我們帶回了課堂上老師聲嘶力竭向我們傳授的內容——兩角和與差:

cos(α+β)=cosα·cosβ-sinα·sinβ
cos(α-β)=cosα·cosβ+sinα·sinβ
sin(α+β)=sinα·cosβ+cosα·sinβ
sin(α-β)=sinα·cosβ-cosα·sinβ

回憶起老師傳授給我們的知識之后,接下來結合P1的坐標表示形式我們就可以把P2的坐標換一個表示形式了。

x2 = L·(sinα·cosβ+cosα·sinβ) = cosβ·x1 + sinβ·y1

y2 = L·(cosα·cosβ-sinα·sinβ) = cosβ·y1 - sinβ·x1

z2 = z1

因此,在已知P1點坐標以及旋轉角度β的情況下,我們就可以根據以上公式分別求出P2點坐標的各個分量。如果再結合上一小節中平移一個點的公式來看,我們可以發現似乎並不需要矩陣,而僅僅通過兩組表達式就能實現坐標的變換。但是......

0x03 帶來便捷的矩陣

當然,從理論上講我們的確可以只通過數學公式就能實現變換,但實際的情況卻是在變換十分復雜時,直接使用數學表達式來進行運算也是相當繁復的。因此,在現實中常常使用矩陣(由m × n個標量組成的長方形數組)來表示諸如平移、旋轉以及縮放等線性變換。而另一個更有趣的事實是,當兩個變換矩陣A和B的積為P=AB時,則變換矩陣P相當於A和B所代表的變換。舉一個例子,若A為旋轉矩陣,B為平移矩陣,則矩陣P就能夠實現旋轉和平移變換。不過需要注意的是,矩陣乘法不符合交換律,因此AB和BA並不相等。
說了這么多,我們似乎還是沒有回答為什么三維空間需要一個4×4矩陣來實現變換呢?下面我們就帶着這個問題,分別看看3×3矩陣和4×4矩陣的使用吧。

3×3矩陣和旋轉

首先,我們先來看一個矩陣乘以一個三維矢量的算式:

可以看到該矩陣為一個3×3的矩陣,矩陣的右側是點P1的坐標,而矩陣的左側則是點P2的坐標。根據這個表達式,我們可以求出x2、y2、z2的值:

x2 = a·x1 + b·y1 + c·z1

y2 = d·x1 + e·y1 + f·z1

z2 = g·x1 + h·y1 + i·z1

為了將矩陣等式和之前小節的數學表達式聯系起來,下面我們就將旋轉表達式和該矩陣等式做一個對比。

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

通過對比x2,我們可以發現a=cosβ,b=sinβ,c=0;
對比y2,也可以發現d=-sinβ,e=cosβ,f=0;
最后對比z2,可以確定g=0,h=0,i=1;
將這個結果帶入到之前的矩陣中,我們的等式就可以變成下面這個樣子:

也就是說,通過這個3×3的變換矩陣,我們就已經實現了三維空間的旋轉變換。那么為什么還需要使用4×4矩陣呢?

搞不定的平移,4×4矩陣來救場

我們已經通過一個3×3矩陣搞定了旋轉變換,顯然如果這個3×3矩陣真的是完美的解決變換的方案的話,那么它顯然也必須要適合於其他的變換,例如平移。但是它到底能否滿足平移的需求呢?下面我們還是通過對比矩陣等式和數學表達式的方式,來尋找答案。

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

通過對比,我們發現平移和旋轉之間很有趣的一個區別,那就是平移的表達式中帶有常量Δx,而無論是旋轉的表達式還是矩陣等式中都不存在這樣一個常量能夠與之對應。那么問題就來,我們沒有辦法使用3×3的矩陣來表示平移。這個問題該如何解決呢?答案其實很簡單,那就是使用4×4矩陣來實現。但是隨之而來的一個問題就是如何讓一個三維坐標和一個4×4的矩陣相乘呢?

齊次坐標

為了解決三維矢量和4×4矩陣相乘的問題,我們機智的為三維矢量添加了第四個分量,這樣之前的三維矢量(x,y,z)就變成了四維的(x,y,z,w),這樣由4個分量組成的矢量便被稱為齊次坐標。需要說明的是,齊次坐標(x,y,z,w)等價於三維坐標(x/w,y/w,z/w),因此只要w分量的值是1,那么這個齊次坐標就可以被當作三維坐標來使用,而且所表示的坐標就是以x,y,z這3個值為坐標值的點。
因此,為了和4×4矩陣相乘,我們的P1點坐標就變成了(x1,y1,z1,1)。而矩陣等式也變成了下面這個樣子:

我們再將這個新的矩陣等式和平移的數學表達式做一番對比:

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

通過對比x2,我們可以發現a=1,b=0,c=0,d=Δx;
對比y2,也可以發現e=0,f=1,g=0,h=Δy;
再對比z2,可以確定i=0,j=0,k=1,l=Δz;
最后還可以根據表達式求出m=0,n=0,o=0,p=1;
這樣,我們就求出了我們的4×4的平移矩陣:

0x04 總結

寫到這里,不知各位是否還記得之前在介紹矩陣乘法的時候我有提到過兩個變換矩陣A和B的積P=AB,相當於A和B所代表的變換。事實上在游戲編程中,常常需要把一連串的變換預先通過計算成為單一矩陣,所以就不能即存在3×3的矩陣又存在4×4的矩陣。而將3×3矩陣拓展成4×4矩陣還是相對更加容易的。這樣,就通過一個4×4矩陣整合了平移矩陣、旋轉矩陣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM