2013-03-23 79 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 

但是他们选择存储他们的矩阵使得在内存中表示实际上是相同的(直到我们进入着色器和一些表述需要调换......)