THREE.Matrix4源码详解
- THREE.Matrix
- set函数:
- copyPosition函数(重要)
- makeTranslation(得到平移矩阵)
- transpose(矩阵转置)
- setPosition(设置平移参数)
- getInverse(矩阵求逆)
- scale(矩阵*scale)
- makeRotationX(传入角度得到绕X轴的旋转矩阵和备注不一样)
- makeRotationY(传入角度得到绕Y轴的旋转矩阵和备注一样)
- makeRotationZ(传入角度得到绕Z轴的旋转矩阵和备注不一样)
- makeRotationAxis(传入参数得到旋转矩阵)
- makeScale(传入参数得到缩放矩阵)
- compose(重要)(传入position, quaternion, scale构建矩阵)
- decompose(获取矩阵中的position, quaternion, scale信息)
- makePerspective函数(构建透视投影矩阵)
- makeOrthographic函数(构建平视投影矩阵)
- 备注
THREE.Matrix
数学上正常矩阵排列是
// 11 12 13 14
// 21 22 23 24
// 31 32 33 34
// 41 42 43 44
默认是单位矩阵构造如下所示(列优先):
function Matrix4() {
this.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
// 实际存储元素编号如下所示
// 11(0) 21(1) 31(2) 41(3)
// 12(4) 22(5) 32(6) 42(7)
// 13(8) 23(9) 33(10) 43(11)
// 14(12) 24(13) 34(14) 44(15)
}
set函数:
set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
var te = this.elements;
te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
return this;
}
可以证明THREE中矩阵存储方式是以列优先方式
copyPosition函数(重要)
copyPosition: function ( m ) {
var te = this.elements, me = m.elements;
te[ 12 ] = me[ 12 ];//从上面得知te[ 12 ]对应的是数学教材里面的 14
te[ 13 ] = me[ 13 ];//从上面得知te[ 13 ]对应的是数学教材里面的 24
te[ 14 ] = me[ 14 ];//从上面得知te[ 14 ]对应的是数学教材里面的 34
// 对应数学上的矩阵是
// 11 12 13 14(x平移量)
// 21 22 23 24(y平移量)
// 31 32 33 34(z平移量)
// 41 42 43 44
return this;
}
makeTranslation(得到平移矩阵)
makeTranslation: function ( x, y, z ) {
this.set(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
);
return this;
},
transpose(矩阵转置)
setPosition(设置平移参数)
setPosition: function ( x, y, z ) {
var te = this.elements;
if ( x.isVector3 ) {
te[ 12 ] = x.x;
te[ 13 ] = x.y;
te[ 14 ] = x.z;
} else {
te[ 12 ] = x;
te[ 13 ] = y;
te[ 14 ] = z;
}
return this;
},
getInverse(矩阵求逆)
scale(矩阵*scale)
scale: function ( v ) {
var te = this.elements;
var x = v.x, y = v.y, z = v.z;
te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
return this;
},
makeRotationX(传入角度得到绕X轴的旋转矩阵和备注不一样)
makeRotationX: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
1, 0, 0, 0,
0, c, - s, 0,
0, s, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationY(传入角度得到绕Y轴的旋转矩阵和备注一样)
makeRotationY: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
c, 0, s, 0,
0, 1, 0, 0,
- s, 0, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationZ(传入角度得到绕Z轴的旋转矩阵和备注不一样)
makeRotationZ: function ( theta ) {
var c = Math.cos( theta ), s = Math.sin( theta );
this.set(
c, - s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
//计算得到如下,和下面一样和备注不一样
//cos -sin 0 0
//sin cos 0 0
//0 0 1 0
//0 0 0 1
return this;
}
makeRotationAxis(传入参数得到旋转矩阵)
makeRotationAxis: function ( axis, angle ) {
// Based on http://www.gamedev.net/reference/articles/article1199.asp
var c = Math.cos( angle );
var s = Math.sin( angle );
var t = 1 - c;
var x = axis.x, y = axis.y, z = axis.z;
var tx = t * x, ty = t * y;
this.set(
tx * x + c, tx * y - s * z, tx * z + s * y, 0,
tx * y + s * z, ty * y + c, ty * z - s * x, 0,
tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
0, 0, 0, 1
);
//假如是绕x轴,计算得到如下,和备注里面的好像不一样
// 1 0 0 0
// 0 cos -sin 0
// 0 sin cos 0
// 0 0 0 1
return this;
}
makeScale(传入参数得到缩放矩阵)
makeScale: function ( x, y, z ) {
this.set(
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
);
return this;
}
compose(重要)(传入position, quaternion, scale构建矩阵)
compose: function ( position, quaternion, scale ) {
var te = this.elements;
var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
var x2 = x + x, y2 = y + y, z2 = z + z;
var xx = x * x2, xy = x * y2, xz = x * z2;
var yy = y * y2, yz = y * z2, zz = z * z2;
var wx = w * x2, wy = w * y2, wz = w * z2;
var sx = scale.x, sy = scale.y, sz = scale.z;
te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
te[ 1 ] = ( xy + wz ) * sx;
te[ 2 ] = ( xz - wy ) * sx;
te[ 3 ] = 0;
te[ 4 ] = ( xy - wz ) * sy;
te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
te[ 6 ] = ( yz + wx ) * sy;
te[ 7 ] = 0;
te[ 8 ] = ( xz + wy ) * sz;
te[ 9 ] = ( yz - wx ) * sz;
te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
te[ 11 ] = 0;
te[ 12 ] = position.x;
te[ 13 ] = position.y;
te[ 14 ] = position.z;
te[ 15 ] = 1;
return this;
}
decompose(获取矩阵中的position, quaternion, scale信息)
decompose: function ( position, quaternion, scale ) {
var te = this.elements;
var sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();//11 21 31
var sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();//12 22 32
var sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();//13 23 33
// if determine is negative, we need to invert one scale
var det = this.determinant();//暂时没看懂
if ( det < 0 ) sx = - sx;//暂时没看懂
position.x = te[ 12 ];//14
position.y = te[ 13 ];//24
position.z = te[ 14 ];//34
// scale the rotation part
_m1.copy( this );
var invSX = 1 / sx;
var invSY = 1 / sy;
var invSZ = 1 / sz;
_m1.elements[ 0 ] *= invSX;
_m1.elements[ 1 ] *= invSX;
_m1.elements[ 2 ] *= invSX;
_m1.elements[ 4 ] *= invSY;
_m1.elements[ 5 ] *= invSY;
_m1.elements[ 6 ] *= invSY;
_m1.elements[ 8 ] *= invSZ;
_m1.elements[ 9 ] *= invSZ;
_m1.elements[ 10 ] *= invSZ;
quaternion.setFromRotationMatrix( _m1 );
scale.x = sx;
scale.y = sy;
scale.z = sz;
return this;
}
makePerspective函数(构建透视投影矩阵)
makeOrthographic函数(构建平视投影矩阵)
备注
1.glsl中mat的使用
mat4 mattest = mat4(1,0,0,0,0,1,0,0,0,0,1,0,0.5,0.5,0.0,1.0);// 列优先
vec4 mvPosition = projectionMatrix * viewMatrix * mattest * modelMatrix * vec4( position, 1.0 );
mat4 matrix4 = mat4(
1.1,2.1,3.1,4.1,
1.2,2.2,3.2,4.2,
1.3,2.3,3.3,4.3,
1.4,2.4,3.4,4.4
);
// 访问矩阵matrix4的第二列
vec4 v4 = matrix4[1];//返回值vec4(1.2,2.2,3.2,4.2)
// 访问矩阵matrix4的第三列第四行对应的元素
float f = matrix4[2][3];//返回4.3
2.平移变化
//声明一个四维向量pos,xyz的坐标是0.8,3.2,6.8,假设表示一个顶点位置坐标
vec4 pos = vec4(0.0,3.2,6.8,1.0);
//创建平移矩阵(表示沿x轴平移-0.4)
//1 0 0 -0.4
//0 1 0 0
//0 0 1 0
//0 0 0 1
mat4 m4 = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, -0.4,0,0,1);
//平移矩阵m4左乘顶点坐标pos(vec4类型数据可以理解为线性代数中的nx1矩阵,即列向量)
// 顶点位置坐标pos进行平移变换
vec4 newPos= m4*pos;//平移后结果:newPos = vec4(-0.4,3.2,6.8,1.0)
3.旋转变换
// 顶点齐次坐标pos
vec4 pos = vec4(0.0,3.2,6.8,1.0);
float radian = radians(30.0);//角度转弧度
float cos = cos(radian);//求解旋转角度余弦值
float sin = sin(radian);//求解旋转角度正弦值
//旋转矩阵mx,创建绕x轴旋转矩阵
//1 0 0 0
//0 cos sin 0
//0 -sin cos 0
//0 0 0 1
mat4 mx = mat4(1,0,0,0, 0,cos,-sin,0, 0,sin,cos,0, 0,0,0,1);
//旋转矩阵my,创建绕y轴旋转矩阵
//cos 0 sin 0
//0 1 0 0
//-sin 0 cos 0
//0 0 0 1
mat4 my = mat4(cos,0,-sin,0, 0,1,0,0, sin,0,cos,0, 0,0,0,1);
//旋转矩阵mz,创建绕z轴旋转矩阵
//cos sin 0 0
//-sin cos 0 0
//0 0 0 0
//0 0 0 1
mat4 mz = mat4(cos,0,-sin,0, 0,1,0,0, sin,0,cos,0, 0,0,0,1);
//三个旋转矩阵、顶点齐次坐标连乘
vec4 newPos = mx*my*mz*pos;
4.缩放变换(简单)