1. 概述
three.js中自带了矩阵运算库,不过在使用的过程中总是容易混淆。不知道是行主序还是列主序,前乘和后乘也很容易弄反。就在这里辨析一下。
2. 详论
2.1. 行主序与列主序列
很早就知道OpenGL中使用的矩阵是列主序,而Direct3D中使用的是行主序,但是没什么具体的体会,还直接弄混淆了。应该来说,无论Direct3D还是OpenGL,使用的矩阵应该都能线性代数中描述的矩阵是等价的,只不过存储方式不同。矩阵在编程实现中一般会表示成数组的形式,以线性代数中描述的矩阵为标准,行主序就是依次按行存储,而列主序就是依次按列存储。
在threeJS中:
var A = new THREE.Matrix4();
A.set(1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
console.log(A);
var B = new THREE.Matrix4();
B.set(16, 15, 14, 13,
12, 11, 10, 9,
8, 7, 6, 5,
4, 3, 2, 1);
console.log(B);
var C = new THREE.Matrix4();
C.multiplyMatrices (A, B);
console.log(C);
其运行结果为:
在网上找一个在线矩阵计算器,相对应的计算结果如下:
因此可以认为,threejs矩阵内部储存形式为列主序,表达和描述的仍然是线性代数中行主序,set()函数就是以行主序接受矩阵参数的。
2.2. 矩阵乘法
前面用到的矩阵乘法是新建了一个矩阵,调用multiplyMatrices。threejs矩阵还有前乘和后乘的区别,也很容易混淆。
在threeJS中矩阵的后乘方法为multiply():
var A = new THREE.Matrix4();
A.set(1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
var B = new THREE.Matrix4();
B.set(16, 15, 14, 13,
12, 11, 10, 9,
8, 7, 6, 5,
4, 3, 2, 1);
A.multiply(B);
console.log(A);
console.log(B);
其运行结果为:
表明后乘方法multiply()的结果就是(A * B)。
反过来,使用前乘方法premultiply():
var A = new THREE.Matrix4();
A.set(1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
var B = new THREE.Matrix4();
B.set(16, 15, 14, 13,
12, 11, 10, 9,
8, 7, 6, 5,
4, 3, 2, 1);
A.premultiply(B);
console.log(A);
console.log(B);
其运行结果为:
对比在线矩阵计算器中的计算结果:
表明前乘方法premultiply()的结果是(B * A)。