化石原创文章,转载请注明来源并保留原文链接


这个是即使看了维基上的图文解释,也不容易搞清楚的概念。但是拿出代码实现来看,就非常清楚。

所谓Column-major,即在连续的内存中,表现的元素是列-连续的。而Row-major,则是行-连续的。维基上用二维数组来解释这个概念,在我看来反而让人混淆。其实用一维看这个问题更清楚。

比如,如下矩阵,在数学书上这么表示:

Row-major matrix AND Column-major

图是借来的,带红色线的是Row-major,湖蓝的是Column-major。去除线两个矩阵其实是一样的。那什么导致了它们会有所谓的,Row-major和Column-major差异?

答案是:在程序里存储的连续性方式。

现在把上面的两个矩阵在你心里抹去那些线,两个矩阵就是同一个矩阵。我们在写代码的时候,必须就这个形式上矩阵元素做存储,我这里以javascript代码做演示:

function Matrix3(a11, a21, a31,
                 a12, a22, a32,
                 a13, a23, a33) {

     //column major
     this[0] = a11 || 0.0;
     this[1] = a21 || 0.0;
     this[2] = a31 || 0.0;
     this[3] = a12 || 0.0;
     this[4] = a22 || 0.0;
     this[5] = a32 || 0.0;
     this[6] = a13 || 0.0;
     this[7] = a23 || 0.0;
     this[8] = a33 || 0.0;
}

上面的代码中,类Matrix3的构造,存储9个参数带进来的元素。由this的下标0、1、2、3、4、5、6、7、8连续着看,我们是按照先“列”、再“行”的方式进行整个过程。这个就叫Column-major。 回到上面的图,正好是我们的湖蓝色线的走向。

参数命名好的话就是这样:

function Matrix3(column0Row0, column0Row1, column0Row2,
                 column1Row0, column1Row1, column1Row2,
                 column2Row0, column2Row1, column2Row2) {

     //column major
     this[0] = column0Row0 || 0.0;
     this[1] = column0Row1 || 0.0;
     this[2] = column0Row2 || 0.0;
     this[3] = column1Row0 || 0.0;
     this[4] = column1Row1 || 0.0;
     this[5] = column1Row2 || 0.0;
     this[6] = column2Row0 || 0.0;
     this[7] = column2Row1 || 0.0;
     this[8] = column2Row2 || 0.0;
}

那么很显然,Row-major写法的话,就是让0到7的元素以红色线的顺序存储既是。这里我就不贴代码了。

如果是现实中加入了translation的矩阵,则

OpenGL标准中说到(下文第2段,黑体):

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. 

出处:  https://www.opengl.org/archives/resources/faq/technical/transformations.htm 

第一段(斜体,特别是黑色)中OpenGL标准定义,一个4×4的矩阵-包含了16个元素,作为translation的x、y、z应该放在第13,14,15位置(正整数,以1位起始)。

在OpenGL的很多地方,可以看到纸面的表述,矩阵如下:

1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 0

但是在内存中,其实它是如下存放(先摆行里的元素,也就是先第一行,再第二行):

[1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, z, 0]

所以,OpenGL标准里说的矩阵都是“Column-major”。

所以,如果写自己的矩阵库,概念(名称)重要,重要的是要符合OpenGL的标准:连续的内存中,13、14、15个元素是translation的x、y、z。


化石原创文章,转载请注明来源并保留原文链接