c++ - C++ 和 OpenGL 矩阵顺序之间的混淆(行优先 vs 列优先)

标签 c++ math opengl matrix

我对矩阵定义感到非常困惑。我有一个矩阵类,它包含一个 float[16],我认为它是行主要的,基于以下观察:

float matrixA[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
float matrixB[4][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };

matrixAmatrixB 在内存中都具有相同的线性布局(即所有数字都按顺序排列)。根据http://en.wikipedia.org/wiki/Row-major_order这表示以行为主的布局。

matrixA[0] == matrixB[0][0];
matrixA[3] == matrixB[0][3];
matrixA[4] == matrixB[1][0];
matrixA[7] == matrixB[1][3];

因此,matrixB[0] = 第 0 行,matrixB[1] = 第 1 行,等等。同样,这表示行优先布局。

当我创建一个如下所示的翻译矩阵时,我的问题/困惑出现了:

1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1

在内存中的布局为,{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.

然后当我调用 glUniformMatrix4fv ,我需要将转置标志设置为 GL_FALSE,表明它是列优先的,否则无法正确应用诸如平移/缩放等转换:

If transpose is GL_FALSE, each matrix is assumed to be supplied in column major order. If transpose is GL_TRUE, each matrix is assumed to be supplied in row major order.

为什么我的矩阵(看起来是行优先的)需要作为列优先传递给 OpenGL?

最佳答案

opengl 文档中使用的矩阵表示法没有描述 OpenGL 矩阵的内存布局

如果您认为放弃/忘记整个“行/列主要”的事情会更容易。这是因为除了行/列专业之外,程序员还可以决定他希望如何在内存中布置矩阵(相邻元素是形成行还是列),除了符号,这会增加困惑。

OpenGL 矩阵有 same memory layout as directx matrices .

x.x x.y x.z 0
y.x y.y y.z 0
z.x z.y z.z 0
p.x p.y p.z 1

{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 }
  • x、y、z 是描述矩阵坐标系(相对于全局坐标系内的局部坐标系)的三分量 vector 。

  • p 是描述矩阵坐标系原点的三分量 vector 。

这意味着翻译矩阵应该像这样在内存中布局:

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }.

就这样吧,剩下的应该很容易了。

---来自旧的opengl faq的引用--


9.005 Are OpenGL matrices column-major or row-major?

For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix, where indices are numbered from 1 to 16 as described in section 2.11.2 of the OpenGL 2.1 Specification.

Column-major versus row-major is purely a notational convention. Note that post-multiplying with column-major matrices produces the same result as pre-multiplying with row-major matrices. The OpenGL Specification and the OpenGL Reference Manual both use column-major notation. You can use any notation, as long as it's clearly stated.

Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion in the OpenGL programming community. Column-major notation suggests that matrices are not laid out in memory as a programmer would expect.


我要更新这个 9 年前的答案。

一个数学矩阵被定义为m x n 矩阵。其中m 的数量,n 的数量。为了完整起见,行是水平的,列是垂直的。当用数学符号 Mij 表示矩阵元素时,第一个元素 (i) 是行索引,第二个元素 (j) 是列索引。当两个矩阵相乘时,即 A(m x n) * B(m1 x n1),得到的矩阵具有来自第一个参数的行数 (A),并且 number第二个参数 (B) 的列数,第一个参数 (A) 的列数必须与第二个参数 (B) 的行数匹配>)。所以 n == m1。到此为止,是吗?

现在,关于内存布局。您可以通过两种方式存储矩阵。行优先和列优先。 Row-major 意味着有效地你有一个又一个线性排列的行。所以,元素从左到右,一行接一行。有点像英文文本。 Column-major 意味着你有一个接一个地线性排列。所以元素从左上角开始,从上到下。

例子:

//matrix
|a11 a12 a13|
|a21 a22 a23|
|a31 a32 a33|

//row-major
[a11 a12 a13 a21 a22 a23 a31 a32 a33]

 //column-major
[a11 a21 a31 a12 a22 a32 a13 a23 a33]

现在,有趣的部分来了!

有两种方法可以将 3d 变换存储在矩阵中。 正如我之前提到的,3d 中的矩阵本质上存储坐标系基 vector 和位置。因此,您可以将这些 vector 存储在矩阵的行或列中。当它们存储为列时,您将矩阵与列 vector 相乘。像这样。

//convention #1
|vx.x vy.x vz.x pos.x|   |p.x|   |res.x|
|vx.y vy.y vz.y pos.y|   |p.y|   |res.y|
|vx.z vy.z vz.z pos.z| x |p.z| = |res.z|
|   0    0    0     1|   |  1|   |res.w| 

但是,您也可以将这些 vector 存储为行,然后将行 vector 与矩阵相乘:

//convention #2 (uncommon)
                  | vx.x  vx.y  vx.z 0|   
                  | vy.x  vy.y  vy.z 0|   
|p.x p.y p.z 1| x | vz.x  vz.y  vz.z 0| = |res.x res.y res.z res.w|
                  |pos.x pos.y pos.z 1|   

所以。约定#1 经常出现在数学课本中。约定 #2 在某个时候出现在 DirectX sdk 中。两者都有效。

关于这个问题,如果您使用约定 #1,那么您的矩阵是列优先的。如果您使用约定 #2,那么它们是行专业的。但是,两种情况下的内存布局是一样的

[vx.x vx.y vx.z 0 vy.x vy.y vy.z 0 vz.x vz.y vz.z 0 pos.x pos.y pos.z 1]

这就是为什么我说 9 年前更容易记住哪个元素是哪个。

关于c++ - C++ 和 OpenGL 矩阵顺序之间的混淆(行优先 vs 列优先),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17717600/

相关文章:

C++——指针传递问题

c++ - _endthreadex(0) 挂起

c++ - 插入排序打印错误输出

java.math.BigInteger 无法转换为 java.math.BigDecimal

c++ - 递归幂函数

java - 如何在 Java 3d 场景上绘制 2d 叠加层?

c++ - 到达顶部后将正方形放在左侧

c++ - 我如何拍摄 stdafx.h?

c++ - 嵌套命名空间是一种矫枉过正吗?

javascript - Math.cos 不准确