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


77

我对矩阵定义感到完全困惑。我有一个矩阵类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 } };

matrixA并且matrixB两者在存储器中的相同的线性布局(即,所有数字是按顺序)。根据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,表明它是列主要的,否则诸如transform / scale等的转换将无法正确应用:

如果转置为GL_FALSE,则假定每个矩阵以列主序提供。如果转置为GL_TRUE,则假定每个矩阵按行主要顺序提供。

为什么我的矩阵(主要是行主要的)需要作为列主要的传递给OpenGL?


您如何确定自己“需要将转置标志设置为” GL_FALSE?您如何使用制服?
Angew不再为SO

@Angew我需要将转置标志设置为GL_FALSE,否则平移/缩放等不起作用,它们将转置变换应用于视图。
马克·英格拉姆

1
我在这里已经详细说明了这个问题。“矩阵不是变换”:bit.ly/1cPINCm
DuckMaestro

在灯架上有一个很好的文章上Scratchapixel:scratchapixel.com/lessons/3d-basic-lessons/lesson-4-geometry/...
user18490 2014年

12
当人们来回投票表决一个问题(或答案)并且不留下任何反馈时,这真让我感到烦恼
Mark Ingram 2014年

Answers:


69

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

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

OpenGL矩阵的存储布局与Directx矩阵相同

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是描述矩阵坐标系(相对于全局坐标系的局部坐标系)的3分量向量。

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

这意味着转换矩阵应像下面这样放在内存中:

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

保留它,其余的应该很容易。

---来自旧的opengl常见问题的引用-


9.005 OpenGL矩阵是列优先还是行优先?

出于编程目的,OpenGL矩阵是16值数组,基本向量在内存中连续放置。转换组件占据16元素矩阵的第13、14和15个元素,其中索引的编号从1到16,如OpenGL 2.1规范的2.11.2节所述。

列主行与行主行纯粹是一种符号约定。请注意,使用列主矩阵进行事后乘法的结果与使用行主矩阵进行事前乘法的结果相同。《 OpenGL规范》和《 OpenGL参考手册》都使用主要列表示法。您可以使用任何符号,只要明确说明即可。

可悲的是,在规范和蓝皮书中使用列优先格式已经在OpenGL编程社区中引起了无尽的困惑。列为主的表示法表明,矩阵并未像程序员期望的那样在内存中布置。



2
您如何表示相同的内存布局?给定我原始帖子中的示例,它表明矩阵的内存布局主要是行(因为这就是C将内存布置在二维数组中的方式)。那么,当内存布局不匹配时,为什么需要设置标志来告诉OpenGL我正在使用列优先的?
马克·英格拉姆

2
@MarkIngram:行/列是仅在文档中使用的表示法。在D3DMatrix和OpenGL矩阵中,转换元素在内存中的位置相同-索引/偏移量为12、13、14(或16个元素数组的第13、14和15个元素)的元素。
SigTerm

2
@MarkIngram:换句话说,OpenGL文档中使用的矩阵符号未描述OpenGL矩阵在内存中的布局。
SigTerm

7
主要列和主要行是关于矩阵在内存中的布局方式。看到。例如。本书Golub-Matrix Computations,或关于行大的Wiki文章。OpenGL常见问题解答有误或不明确。将向量视为行向量还是列向量是一个单独的问题,这也决定了应将基本向量保留在列还是行中。(有时用术语行主要来表示这一点,这增加了混乱。)GLSL的矩阵数据类型是列主要的,惯例是将向量视为列向量。在内存中,D3D和OpenGL约定最终是相同的。
darklon 2014年

4
您能否对您认为列/行主要的含义有何解释?我完全不理解“忘记……”的话。根据Wikipedia所述,这些术语定义了内存布局,这是这里最重要的部分。我为什么要忘记那个?
Andreas Haferburg '16

66

用SigTerm和dsharlet总结答案:在GLSL中转换向量的通常方法是将向量乘以转换矩阵:

mat4 T; vec4 v; vec4 v_transformed; 
v_transformed = T*v;

为了使其正常工作,OpenGL期望TSigTerm所述的内存布局为:

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

也称为“专栏专业”。但是,在着色器代码中(如注释所示),您将矢量右乘以变换矩阵:

v_transformed = v*T;

仅在T转置后才产生正确的结果,即具有布局

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

(即“行专业”)。由于您已经为着色器(即行专业版)提供了正确的布局,因此无需设置transpose标志glUniform4v


7
我认为最好的答案。这是图形学生的完美范例。在数学中,向量之一是水平的,而另一个是垂直的(其他乘积未定义)。我知道编程时我们会忘记大多数数学形式主义XD
CoffeDeveloper 2015年

为什么不忘记这种形式主义呢?从编程的角度来看,这将更加有意义。
whossname

15

您正在处理两个单独的问题。

首先,您的示例正在处理内存布局。您的[4] [4]数组是行主要的,因为您使用了C多维数组建立的约定来匹配线性数组。

第二个问题是关于如何解释程序中矩阵的约定。glUniformMatrix4fv用于设置着色器参数。无论您的变换计算的行向量列向量变换是你如何在你的着色器代码使用矩阵的问题。因为您说需要使用列向量,所以我假设您的着色器代码使用矩阵A和列向量x来计算x' = A x

我认为glUniformMatrix的文档令人困惑。对转置参数的描述只是说矩阵已转置或不是转置的一种真正的回旋方式。OpenGL本身只是将数据传输到着色器中,无论是否要转置它,都是您应该为程序建立的约定。

此链接有一些更深入的讨论:http : //steve.hollasch.net/cgindex/math/matrix/column-vec.html


我对着色器中的矩阵没有任何幻想。它看起来像这样:gl_Position = vec4(v_xy, 0.0, 1.0) * v_ViewMatrix * v_ProjectionMatrix;
Mark Ingram

@MarkIngram可能看起来并不花哨,但很重要。这告诉您关于如何解释转换矩阵的约定。
dsharlet

1
它告诉我什么(即约定是什么,以及它如何显示我)?:)
马克·英格拉姆

1
@MarkIngram告诉您正在将位置解释为行向量。当您想通过矩阵A变换向量x时,可以计算x'^ T = x ^ T A。这不是一般数学中的标准,而是计算机图形学中的常见标准(不幸的是,这会引起很多混乱)。
dsharlet

2
所以我应该切换乘法的顺序?而不是vector x model x view x projection;,这样做projection x view x model x vector;
马克·英格拉姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.