【THREE源码解析篇】THREE.Matrix4源码详解

本文详细解析THREE.Matrix4类中的重要函数,包括copyPosition、makeTranslation、transpose、setPosition、getInverse、scale、旋转与缩放矩阵的构建,以及compose和decompose函数用于组合和分解矩阵。同时介绍了矩阵在三维空间中的应用,如平移、旋转和缩放变换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.缩放变换(简单)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值