矩陣真的是乙個很神奇的數學工具, 雖然單純從數學上看, 它並沒有什麼特別的意義, 但一旦用到空間中的座標變換,它就「一遇風雲便成龍」, 大顯神威了。簡單的工具實現了複雜的功能,便預示著要理解它我們還是要花上點功夫的。下面就簡單介紹一下opengl中的轉換矩陣。
1 轉換矩陣的原理
opengl中的轉換矩陣是這樣定義的:
[xx, yx, zx, tx]
[xy, yy, zy, ty]
m = [xz, yz, zz, tz]
[0, 0, 0, 1 ]
其實我們可以這麼理解這個變換矩陣, 它表示了乙個區域性座標系, 這個區域性座標系,是把世界座標系的原點移到(tx, ty, tz),把x軸轉到(xx, xy, xz), y軸轉到(yx, yy, yz),z軸轉到(zx, zy, zz)而形成的。用它來變換乙個世界座標系中的點v, 就是得到這個區域性座標系中的點。
要證明這一點很容易, 我們從可以從更通用的方面來考慮,假設我們用矩陣ma來表示座標系a, mb來表示座標系b, mt表示從a到b的轉換, 那麼:
mt * ma = mb
mt * ma * (ma)^-1 = mb * (ma)^-1
矩陣雖然不符合乘法交換律,但其符合乘法結合律, 於是:
mt* (ma * (ma)^-1) = mb * (ma)^-1
mt = mb * (ma)^-1
這就是a到b轉換矩陣的表示式,現在我們從世界座標系轉換到區域性座標系,a表示的世界座標系是個單位矩陣,所以:
mt = mb
即區域性座標系的矩陣表示就是從世界座標系到區域性座標系的轉換矩陣。
我們再進一步分析,如果我們用這個矩陣來變換乙個點v(vx, vy, vz, 1),需要把這個點右乘變換矩陣
[xx, yx, zx, tx] [vx]
[xy, yy, zy, ty] [vy]
v' = m*t = [xz, yz, zz, tz] * [vz]
[0, 0, 0, 1 ] [1 ]
對於v變換後的x分量,vx' = xx*vx + yx*vy + zx*vz + tx,我們可以發現影響v的x分量的只有x,y,z軸旋轉的x分量和平移的x分量,對於v的y, z分量也是同樣道理。
2 行主序, 列主序
opengl中推薦用一維陣列來表示此轉換矩陣 : typedef glfloat matrix16[16];
為了能快速的訪問x軸, y軸, z軸, 該陣列是按列主序來表示這個矩陣的:
[m0, m4, m8, m12]
[m1, m5, m9, m13]
[m2, m6, m10,m14]
[m3, m7, m11,m15]
這樣, 為了訪問x軸, 即訪問m0, m1, m2,因為他們是連續的儲存空間,所以速度比較快, 相反, 如果我們陣列按行主序來表示這個矩陣:
[m0, m1, m2, m3 ]
[m4, m5, m6, m7 ]
[m8, m9, m10, m11]
[m12, m13, m14, m15]
我們發現為了訪問x軸, 即m0, m4, m8, 是不連續的位址, 因此速度就慢了下來。
所以我們可以知道, opengl為什麼採用列主序的矩陣, 那是因為其所定義的轉換矩陣如果按列主序存入陣列, 我們對x,y,z軸就可以有較快的訪問速度。也就是說, 如果我非要把這個矩陣按列主序的方式存入陣列也可以, 只不過速度慢了點而已。(當然, 我們要告訴opengl我們是按行主序表示的)。
其實, 如果我們換一種方式來表示轉換矩陣:
[xx, xy, xz, 0]
[yx, yy, yz, 0]
m' = [zx, zy, zz, 0]
[tx, ty, tz, 1]
這個矩陣是是前乙個轉換矩陣的轉置,我們把這個矩陣按行主序存入陣列就比較划算了。原因很明顯, 為了快速訪問x軸,我們希望xx, xy, xz是連續儲存的, 那麼自然要按行儲存了。
其實, 如果讓我設計opengl,我會選擇用第二種方式來表示轉換矩陣,原因如下:
如果我要轉換乙個點v, 依次經過三個轉換矩陣l, m, n的轉換, 那麼對於第一種方式:
v' = n*(m*(l*v)) = (n*m*l) * v
我們的組合轉換矩陣是n*m*l, 與我們定義的轉換過程剛好相反, 但是, 如果我們是第二種方式表示的話,我轉換乙個點是左乘轉換矩陣而不是右乘了:
v' = ((v*l)*m)*n = v * (l*m*n)
組合轉換矩陣是按我們變換的順序組合起來的, 就比較直觀了, 然後我們按行主序儲存此矩陣, 速度依然。
3 二維陣列儲存矩陣
很多人有這樣錯誤的認識, 就是在opengl中如果用二維陣列來表示轉換矩陣, 速度就比較慢, 而這種認識或多或少源於《按我們理解的,邏輯上的二維陣列, 其表示為:
[m00, m01, m02, m03]
[m10, m11, m12, m13]
[m20, m21, m22, m23]
[m30, m31, m32, m33]
因為這個邏輯模型, 導致我們產生那種錯誤的認識:
x軸是用m00, m10, m20表示的, 而他們是不連續的, 所以比較慢, 但是, 這只是其邏輯模型, 如果按邏輯模型去理解的話, 一維陣列的邏輯模型是:
[m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15]
那我們是不是可以說, 一維陣列根本不能用來表示矩陣? 當然不是。
其實, 不論是一維陣列還是二維陣列, 其在記憶體中的物理模型都是連續的16個float型的記憶體單元:
一維陣列:[m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15]
二維陣列:[m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33]
看到這裡, 既然一維陣列可以用列主序表示並很快, 為什麼二維陣列就不快了呢?他們除了訪問時的名字不一樣, 本質上並沒有區別啊:
[m00, m10, m20, m30]
[m01, m11, m21, m31]
[m02, m12, m22, m32]
[m03, m13, m23, m33]
我們可以看到,二維陣列按列主序表示的轉換矩陣是這樣的, 訪問x軸即訪問m00, m01, m02, 連續的, 一樣快。
只不過, 這種表示方式和我們所理解的二維陣列的邏輯模型不太統一, 有些不直觀罷了。這一點在opengl紅寶書的說的比較正確:二維陣列的元素m[i][j]將位於opengl變換矩陣的第i列, 第j行, 因此容易產生行列混淆,為了避免行列混淆, 推薦用一維陣列表示。 真正的原因是為了避免行列混淆, 而不是速度。
opengl的矩陣理解
矩陣真的是乙個很神奇的數學工具,雖然單純從數學上看,它並沒有什麼特別的意義,但一旦用到空間中的座標變換,它就 一遇風雲便成龍 大顯神威了。簡單的工具實現了複雜的功能,便預示著要理解它我們還是要花上點功夫的。下面就簡單介紹一下opengl中的轉換矩陣。1 轉換矩陣的原理 opengl中的轉換矩陣是這樣...
OpenGL 向量計算和矩陣轉換
v k v k cos 使用點乘可以很容易測試兩個向量是否正交 orthogonal 或平行 正交意味著兩個向量互為直角 點乘是通過將對應分量逐個相乘,然後再把所得積相加來計算的。叉乘只在3d空間中有定義,它需要兩個不平行向量作為輸入,生成乙個正交於兩個輸入向量的第三個向量。只有當左側矩陣的列數與右...
opengl 矩陣變換
opengl 矩陣變換 opengl 座標系的變換如下圖 我們給我們的圖形,設定好頂點座標後,通過model matrix 變換為世界座標,然後 view matrix相機座標,projection matrix 螢幕座標x,y 1,1 矩陣變換的結果是把三維的世界最終裁剪為二維的螢幕,數學的說法就...