二、 矩陣運算
1. 什么是矩陣
矩陣就是由多組數據按方形排列的陣列,在3D運算中一般為方陣,即M*N,且M=N,使用矩陣可使計算坐標3D坐標變得很方便快捷。下面就是一個矩陣的實例:
看似沒什么特殊的,可是后面你可以看到矩陣的魅力,為什么矩陣這么有效,我也不知道,這個由數學家去論述,我們只要可以用就是了。
2. 向量的點乘和叉乘
向量的點乘和叉乘與矩陣一樣是數學定義,點乘在矩陣運算中起到很重要的作用,稱為內積,叉乘稱為外積,通過叉乘運算可以計算出一個向量,該向量垂直於由兩個向量構成的平面,該向量也稱為該平面的法線。這兩個計算方法在3D運算中的作用就是向量計算工具。
l 點乘公式
其實就是兩個向量的各分量相乘后形成新的向量
l 叉乘公式
Uc=U1* U2
兩個向量進行叉乘的矩陣如下:
其中x1,y1,z1以及x2,y2,z2分別為向量U1和U2的分量,設UC為叉乘的向量積,其計算公式如下:
3. 三維幾何變換矩陣
幾何繪圖中,常常需要將一個模型從一個位置移動到另一個位置,或者將模型進行縮放旋轉,稱為幾何變換。每個模型都存在一個局部的坐標系,在制作模型的時候是不考慮模型在場景中的具體位置的,模型中的所有頂點的坐標值都相對於局部坐標系,而模型在應用中會發生很多變化,其中大部分情況都是由多種變化復合的結果,這些變化涉及很多復雜的運算,因此你必須逐個計算每個頂點因模型旋轉、縮放、位移后相對於世界坐標系的值,這個計算如果僅僅采用一般的三角函數去逐個點處理那簡直會使你望而生畏,計算量無法估量,就算你費好大勁把公式寫好,也許模型因為你某個小錯誤已經面目全非,更別說動畫效果了。
這時候就必須使用矩陣來解決這些問題。在3D計算中采用的是4元坐標系,因此在計算模型變換的時候采用的是4*4的方陣,矩陣結構中,元素編號按先行后列排列,在編程語言中可以用數組儲存,使用循環計算,為便於坐標的批量處理,在繪制和計算一個三維模型前,先計算好所要某種變換所需要的元素填寫入矩陣,然后逐一將模型的所有頂點和矩陣相乘就可以將模型的所有頂點按所希望的變換為新的坐標(除非矩陣元素設置錯誤),這里可以看出,矩陣中的每個數據(元素)是至關重要的,如何產生這些元素將在第三章介紹。
矩陣結構如下。(二維平面則使用3X3的矩陣,原理相同)。
該結構圖中的每個元素都給定了一個編號,編號的代碼分別代表行和列。
4. 變換計算公式
向量和點的變換運算都可以使用矩陣,一個坐標或向量與一個4X4的矩陣進行點乘運算而進行轉換。矩陣中的數據排列可以使用列矩陣,也可以使用行矩陣,但在做乘法時必須要行列交叉做乘積,OPENGL中使用列矩陣。下面表示一個矩陣數組的排列方式以及一個點或向量是如何與矩陣相乘以獲得新坐標的計算公式的。
其中P是原頂點坐標或向量,變換時將當前頂點點P的四個分量分別與矩陣的每個行進行點乘運算:
x’=x*M00+y*M01+z*M02+w*M03
y’=x*M10+y*M11+z*M12+w*M13
z’=x*M20+y*M21+z*M22+w*M23
w=x*M30+y*M31+z*M32+w*M33
由於在3D運算的矩陣中最后一行前3列始終為0,所以w’的結果取決於w,因此可以看出向量與矩陣相乘得到的也是向量。
5. 單位矩陣
有一種特殊的矩陣,由左上右下的元素組成的對角線,如果之上的所有元素都為1,且其它為0,該矩陣則稱為單位矩陣,任何頂點與單位矩陣相乘的結果等於該頂點的原始坐標,即不發生任何變換。
在OPENGL中常使用glLoadIdentity()函數來設置單位矩陣,由於OPENGL是狀態機,所以每次繪制場景前都用來重置之前可能被修改過的矩陣,但是有時繪制一個模型必須在之前的計算結果上進行坐標變換,比如先畫了一輛汽車的車身,然后根據汽車的當前位置繪制車輪,就必須保持原先的矩陣,相對汽車的位置進行變換,而有時卻要從原點開始計算,所以矩陣的管理是通過一系列的矩陣函數操作的,最常用的是矩陣堆棧的操作,但是由於大多數情況,OPENGL的矩陣堆棧深度為32,即只能保存32個矩陣,雖然矩陣堆棧其效率比較快,但是在某些場合32個矩陣是不夠的,為了減少計算機運算負載,必須事先安排好繪制順序,這也是進行類封裝的必要性,不過類的封裝會增加一定的調用開銷。
6. 矩陣相乘
有時候需要對一個模型進行連續多種變換,而每次變換都要將模型的前次所有頂點與矩陣一一相乘,如果對於一個比較復雜的場景進行處理時,其計算量是很可觀的,為了減少計算量,加快場景繪制,采取事先將多種變換矩陣合並,然后對模型所有頂點和矩陣相乘進行一次性矩陣變換。比如要對模型進行先縮放后旋轉。
合並方法是將多個矩陣相乘來計算出復合矩陣。三維變換中參與乘法運算的兩個矩陣都必須是4X4矩陣,相乘時,每個新元素也通過點乘運算后獲得,所得的新矩陣也是4X4的方陣。
矩陣的乘積不可逆的,即MN不等於NM,因此在安排變換時要注意順序,另外,在頂點與復合矩陣相乘的結果是與矩陣合並順序相反的。比如,T是一個平移矩陣,R是一個旋轉矩陣,假如要進行先旋轉后移動的變換順序,合並矩陣的順序必須是M=TR,然后進行p’=MP的 變換,其效果等同於p’=T(RP)。
矩陣相乘的計算公式分解:
復合矩陣計算方式為,將左邊的矩陣M的每個行元素與右邊矩陣N的每列元素進行點乘運算就是新矩陣C的對應的元素。計算順序為,M由上邊第一行開始,提取每行的4個元素,分別與N中左邊第一列開始,提取的4個元素進行點乘運算,運算結果放在C中,並從上到下,從左到右排列,編程時采用雙重循環。
C00=m00*n00+m01*n10+m02*n20+m03*n30
C01=m00*n01+m01*n11+m02*n21+m03*n31
C02=m00*n02+m01*n12+m02*n22+m03*n32
C03=m00*n03+m01*n13+m02*n23+m03*n33
........
C30=m30*n00+m31*n10+m32*n20+m33*n30
C31=m30*n01+m31*n11+m32*n21+m33*n31
C32=m30*n02+m31*n12+m32*n22+m33*n32
C33=m30*n03+m31*n13+m32*n23+m33*n33
如上所述,經過一系列的計算,分別把兩個矩陣合並起來了,形成了新的復合矩陣,編寫這樣的代碼是很容易的。現在我們已經有了幾個基本矩陣計算工具,只要填入適當的參數,我們就可以用循環的方式變換模型的所有頂點,最終實現模型的任意復雜的變換,基本上都是很機械的操作。而剩下的就屬最核心的東西,就是基本矩陣中元素的生成了。