这些函数是列主要还是行主要?

时间:2013-03-23 04:26:55

标签: math graphics 3d transformation linear-algebra

我正在使用矩阵比较两个不同的3D图形线性数学库。以下是两个库中两个类似的Translate函数:

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;
}

(SO用户骄傲的c ++库)

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)。

我在左关联上下文中多次使用了第一个示例,并且它已按预期工作。虽然我没有使用第二个,但作者说它是正确的,但是我很难看到两者格式之间的区别。

2 个答案:

答案 0 :(得分:6)

  

在我看来,这两个都使用相同的格式,因为在第一个索引中都被视为行,第二个索引是列。

外观可能是欺骗性的,但实际上linmath.h中的第一个索引就是列。 C和C ++在如此定义的多维数组中指定

sometype a[n][m];

n m 连续某些元素。如果是行或列主要顺序,则仅取决于您如何解释索引。现在,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和一些数学库使用列主要排序,很好。但是为什么这样做并打破通常的数学约定,在 M i,j 中,索引 i 指定行和列?因为它使东西看起来更好。你看,矩阵只是一堆向量。可以并且通常形成坐标基础系统的向量。

看看这张照片:

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)

那一刻,那不就是身份矩阵吗?事实上确实如此,

然而,因为它是通过堆叠行向量形成的矩阵。矩阵乘法的规则基本上表明,由行向量形成的矩阵通过左关联乘法将行向量变换为行向量。列主矩阵通过右关联乘法将列向量转换为列向量。

现在这不是一个真正的问题,因为左关联可以做与右关联相同的东西,你只需要交换行的列(即转置)所有内容并颠倒操作数的顺序。但是,左&lt;&gt;右行&lt;&gt;列只是我们写东西的符号约定。

典型的数学符号是(例如)

v_clip = P · V · M · v_local

这种符号使得它直观地显示正在发生的事情。此外,在编程中,关键字符=通常指定从右到左的赋值。一些编程语言在数学上受到更多影响,比如Pascal或Delphi,并编写它:=。无论如何有行主要排序,我们必须写它

v_clip = v_local · M · V · P

对大多数数学家来说,这看起来不自然。因为,从技术上讲,M,V和P实际上是线性算子(是的,它们也是矩阵和线性变换),运算符总是介于等式/赋值和变量之间。

这就是为什么我们使用列主要格式:它看起来更好。从技术上讲,它也可以使用行主格式来完成。这与矩阵的内存布局有什么关系?好吧,当你想使用列主要顺序表示法时,你想要直接访问变换矩阵的基矢量,而不是让它们逐个元素地提取它们。通过以列主格式存储数字,访问矩阵的某个基本向量所需的只是线性存储器中的简单偏移。

我不能代表另一个库的代码示例,但是我强烈地假设它将第一个索引视为较慢的递增索引,这使得它在列专业中工作如果受到符号的影响OpenGL的。请记住:专栏专业&amp;正确的关联性==行专业&amp;左派联系。

答案 1 :(得分:2)

发布的片段不足以回答这个问题。它们可以是按行顺序存储的行主矩阵,也可以是按列顺序存储的列主矩阵。

如果你看一下在与适当的矩阵相乘时如何处理向量,可能会更加明显。在行主系统中,您可以期望将矢量视为单行矩阵,而在列主系统中,它同样是单个列矩阵。然后,这决定了矢量和矩阵如何相乘。您只能将带有矩阵的矢量乘以右侧的单个列或左侧的单个行。

GL约定是列专业,因此向量乘以右侧。 D3D是行主要的,因此向量是行并且乘以左边。

在连接变换时需要考虑这一点,以便按正确的顺序应用它们。

即:

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

然而,他们选择存储他们的矩阵,使得内存中的表示实际上是相同的(直到我们进入着色器并且某些表示需要被转置......)