在webGL中通过右手坐标系去思考其中的旋转
- 当物体绕z轴,从x轴正半轴向y轴负半轴逆时针旋转,为正向旋转,反之为负向旋转
- 当物体绕x轴,从y轴正半轴向z轴正半轴逆时针旋转,是正向旋转,反之为负向旋转
- 当物体绕y轴,从z轴正半轴向x轴正半轴逆时针旋转,是正向旋转,反之为负向旋转
思路过程
举例:计算一个顶点A绕z轴旋转后所在B的位置
-
已知点A,以及∠b
-
∠XOB = ∠a+∠b
-
bx=cos(∠XOB)*OA
-
by=sin(∠XOB)*OA
-
利用三角形勾股定理求出OA的长度
const OA = Math.sqrt(ax*ax + ay*ay) //首先计算OA的长度 -
利用三角形的和角公式得出
cos(∠XOB) = cos(∠a+∠b) = cos(a)*cos(b) - sin(a)*cos(b) sin(∠XOB) = sin(∠a+∠b) = cos(b)*sin(a) + sin(b)*cos(a) -
由此求出bx,by
bx=(cos(a)*cos(b) - sin(a)*sin(b))*OA by=(cos(b)*sin(a) + sin(b)*cos(a))*OA -
简化公示 因为:ax = cos(a) * OA, ay = sin(a) * OA
上式化简为
bx = cos(a)*cos(b)*OA - sin(a)*sin(b)*OA by = cos(b)*sin(a)*OA + sin(b)*cos(a)*OA bx = ax*cos(b) - ay*sin(b) by = cos(b)*ay + sin(b)*ax bx = ax*cos(b) - ay*sin(b) by = ax*sin(b) + ay*cos(b) -
由向量和矩阵乘法计算
[x, y, z, w] * [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, ] = [ ax + by + cz + dw, ex + fy + gz + hw, ix + jy + kz + lw, mx + ny + oz + pw, ] // 由以上乘法规则得出 [bx, by, bz, bw] = [ cos(b), -sin(b), 0, 0, sin(b), cos(b), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] * [ax, ay, az, aw] = [ ax*cos(b) + ay*-sin(b) + az*0 + aw*0, ax*sin(b) + ay*cos(b) + az*0 + aw*0, ax*0 + ay*0 + az*1 + aw*0, ax*0 + ay*0 + az*0 + aw*1, ] = [ ax*cos(b) - ay*sin(b), ax*sin(b) + ay*cos(b), az, aw ]
计算过程
const OA = Math.sqrt(ax*ax + ay*ay) //首先计算OA的长度
// 通过三角函数得出bx,by
const [bx, by, bz, bw]
=
[
cos(b)*ax - sin(b)*ay,
sin(b)*ay + cos(b)*ax,
1*az,
1*aw
]
=
[ax, ay, az, aw]
*
[
cos(b), -sin(b), 0, 0,
sin(b), cos(b), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
由以上推导计算点A绕z轴旋转后所在B的位置所需的矩阵为:
[
cos(b), -sin(b), 0, 0,
sin(b), cos(b), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
源码
以下为three.js中分别绕x、y、z轴旋转的源码
makeRotationX( theta ) {
const 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( theta ) {
const 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( theta ) {
const 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
);
return this;
}
注意⚠️
通常在数学中矩阵是列主序,在webGL中矩阵是行主序的,以上都是用行主序的写法,其中的this.set()方法就是在将行主序的矩阵转换为列主序的矩阵
下面是set方法的源码
set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
const 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;
}