2013-03-23 73 views
1

我正在比較使用矩陣的三維圖形的兩個不同的線性數學庫。以下是這兩個庫中的兩個類似的翻譯功能:這些函數是列專業還是行專業?

static Matrix4<T> Translate(T x, T y, T z) 
{ 
    Matrix4 m; 
    m.x.x = 1; m.x.y = 0; m.x.z = 0; m.x.w = 0; 
    m.y.x = 0; m.y.y = 1; m.y.z = 0; m.y.w = 0; 
    m.z.x = 0; m.z.y = 0; m.z.z = 1; m.z.w = 0; 
    m.w.x = x; m.w.y = y; m.w.z = z; m.w.w = 1; 
    return m; 
} 

(C++從SO用戶prideout庫)

static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) 
{  
mat4x4_identity(T); 
T[3][0] = x; 
T[3][1] = y; 
T[3][2] = z; 
} 

(從SO用戶datenwolf linmath C庫)

我是新到這個東西,但我知道矩陣乘法的順序很大程度上取決於您是否使用列主要或行主要格式。

在我眼中,這兩個使用相同的格式,在第一個索引被視爲行,第二個索引是列。也就是說,在x y z都適用於相同的第一個索引。這對我來說意味着行 - 主,因此矩陣乘法是左聯合的(例如,您通常按照該順序執行rotate * translate)。

我已經在左聯合上下文中多次使用第一個示例,並且它一直按預期工作。雖然我沒有使用第二種,但作者說這是正確的聯想,但我很難看到兩者的格式之間的差異。

+0

除了迄今爲止的出色答案之外,我發現這篇有用的文章解釋了這種情況:http://fgiesen.wordpress.com/2012/02/12/row-major-vs-column-major- row-vectors-vs-column-vectors/ – johnbakers 2013-03-24 01:54:43

回答

6

在我看來,這兩個使用相同的格式,因爲在第一個索引被視爲行,第二個索引是列。

看起來可能是騙人的,但事實上linmath.h中的第一個索引是列。 C和C++指定在一個多維數組這樣

sometype a[n][m]; 

定義有Ñ米連續sometype。這時候元件。如果它是行或列主要訂單完全取決於你如何解釋指數。現在的OpenGL定義的4×4矩陣,以下面的線性方案

0 4 8 c 
1 5 9 d 
2 6 a e 
3 7 b f 

如果應用C++多維數組的規則你添加以下列行指定

----> n 

| 0 4 8 c 
| 1 5 9 d 
V 2 6 a e 
m 3 7 b f 

哪個重新映射來索引線性索引到2元組中

0 -> 0,0 
1 -> 0,1 
2 -> 0,2 
3 -> 0,3 
4 -> 1,0 
5 -> 1,1 
6 -> 1,2 
7 -> 1,3 
8 -> 2,0 
9 -> 2,1 
a -> 2,2 
b -> 2,3 
c -> 3,0 
d -> 3,1 
e -> 3,2 
f -> 3,3 

好吧,OpenGL和一些數學庫使用列主要排序,很好。但是,爲什麼做這種方式與通常的數學約定,在中號 I,J指數指定行和Ĵ列打破?因爲它讓事情看起來更好。你看,矩陣只是一堆向量。通常可以形成座標基礎系統的矢量。

看一看這樣的畫面:

A 3 dimensional cartesian coordinate system with right handed base vectors

軸X,Y和Z基本上是載體。它們被定義爲

X = (1,0,0) 
Y = (0,1,0) 
Z = (0,0,1) 

瞬間,那裏看起來像是一個單位矩陣嗎?確實如此,實際上它

但是,由於它是通過堆疊行向量形成矩陣。矩陣乘法的規則基本上表明,由行向量組成的矩陣通過左關聯乘法將行向量轉換成行向量。列主矩陣通過右關聯乘法將列向量轉換爲列向量。

現在這不是一個真正的問題,因爲左聯合可以做與右聯合可以做的事情相同的東西,你只需要交換行(即轉置)所有內容並顛倒操作數的順序。然而左<>右行<>列只是符號約定,我們在其中寫東西。

和典型的數學符號是(例如)

v_clip = P · V · M · v_local 

這種表示法使得它直觀地看到發生了什麼事情。此外,在編程中,關鍵字=通常指定從右向左分配。一些編程語言受數學影響較大,如Pascal或Delphi,並將其編寫爲:=。無論如何,與行主要訂購,我們必須寫它

v_clip = v_local · M · V · P 

並且對大多數數學人來說這看起來不自然。因爲從技術上講,M,V和P實際上是線性算子(是的,它們也是矩陣和線性變換),操作符總是在相等/賦值和變量之間。

這就是爲什麼我們使用列主要格式:它看起來更好。從技術上講,它也可以使用行主格式來完成。這與矩陣的內存佈局有什麼關係?那麼,如果你想使用列主要順序符號,那麼你需要直接訪問變換矩陣的基向量,而不需要它們逐元素地提取它們。以列主格式存儲數字時,訪問矩陣的某個基矢量所需的全部內容都是線性存儲器中的簡單偏移量。

我不能說其他庫的代碼示例,但我強烈地假設,它將第一個索引也視爲較慢的遞增索引,這使得它在列主要工作,如果受到符號的OpenGL。記住:專欄&右結合==行專業&左結合。

+0

+1從狼的嘴巴! – 2013-03-24 05:56:32

+1

很好的答案,謝謝。我認爲有些人更喜歡排行榜的原因有兩個。 1)行向量類似於標準的一維數組,因此編程時感覺直觀。你可能會對此嗤之以鼻,但我已經看到這種記錄是行列專業在計算機圖形學世界中普遍存在的原因之一,儘管數學領域的專欄主要激增。 2)當你的變換從左到右流動時,有些人發現自然地構造變換比較容易,因爲操作順序與編碼順序相匹配:即「先旋轉,然後翻譯」按照相同的順序編碼。 – johnbakers 2013-03-25 01:18:08

+0

我很想你對這個問題的見解:http://stackoverflow.com/questions/16952546/vector-matrix-multiplication-order-can-affect-performance – johnbakers 2013-06-06 02:11:11

2

發佈的片段不足以回答這個問題。它們可以是以行順序存儲的行主矩陣,也可以是按列順序存儲的列主矩陣。

如果您查看向量如何與適當的矩陣相乘時處理,可能會更加明顯。在一個行主系統中,你會期望向量被視爲單行矩陣,而在列主系統中,它將類似地是單列矩陣。這就決定了一個向量和一個矩陣如何相乘。您只能將具有矩陣的向量乘以右邊的單個列或左邊的單個行。

GL約定是列主要的,所以一個向量乘以右邊。 D3D是行優先的,所以向量是行並且與左邊相乘。

在連接轉換時需要考慮這一點,以便它們按正確的順序應用。

即:

GL: 
    V' = CAMERA * WORLD * LOCAL * V 
D3D: 
    V' = V * LOCAL * WORLD * CAMERA 

但是他們選擇存儲他們的矩陣使得在內存中表示實際上是相同的(直到我們進入着色器和一些表述需要調換......)