前言
本文讲述三维旋转的矩阵推导,推导过程遵循下面的规则:
- 本文的坐标系是基于右手坐标系的
- 逆时针旋转为正向旋转
围绕坐标轴的旋转
x x x轴
我们假设旋转的点为
P
P
P
假设旋转之前点
P
P
P的坐标为
(
x
0
,
y
0
,
z
0
)
(x_0,y_0,z_0)
(x0,y0,z0)
当围绕
x
x
x轴做正向旋转,即逆时针旋转,我们取
x
=
x
0
x = x_0
x=x0的平面作为旋转的坐标系平面
此时,我们将旋转就转化为了二维旋转
因为是右手坐标系,所以此时
y
y
y轴向右,
z
z
z轴向上,原点为平面与
x
x
x轴的交点
O
O
O
假设旋转之前点
P
P
P到原点
O
O
O的线段与
y
y
y轴的夹角弧度为
α
\alpha
α
假设旋转的弧度为
β
\beta
β
假设点
P
P
P到原点
O
O
O的距离为
R
R
R
假设旋转之后点
P
P
P的坐标为
(
x
1
,
y
1
,
z
1
)
,
x
1
=
x
0
(x_1,y_1,z_1), x_1 = x_0
(x1,y1,z1),x1=x0
那么,旋转前
y
0
=
c
o
s
(
α
)
∗
R
z
0
=
s
i
n
(
α
)
∗
R
(1)
y_0 = cos(\alpha) \tag{1}*R\\ z_0 = sin(\alpha) *R
y0=cos(α)∗Rz0=sin(α)∗R(1)
旋转后(注意,因为是逆时针旋转,所以旋转后的弧度 = 旋转前弧度 + 旋转弧度)
y
1
=
c
o
s
(
α
+
β
)
∗
R
=
c
o
s
(
α
)
c
o
s
(
β
)
∗
R
−
s
i
n
(
α
)
s
i
n
(
β
)
∗
R
=
y
0
∗
c
o
s
(
β
)
−
z
0
∗
s
i
n
(
β
)
z
1
=
s
i
n
(
α
+
β
)
∗
R
=
s
i
n
(
α
)
c
o
s
(
β
)
∗
R
+
c
o
s
(
α
)
s
i
n
(
β
)
∗
R
=
y
0
∗
s
i
n
(
β
)
+
z
0
∗
c
o
s
(
β
)
x
1
=
x
0
(2)
\begin{aligned} y_1 & = cos(\alpha + \beta)*R \\ & = cos(\alpha)cos( \beta)*R - sin(\alpha)sin( \beta)*R\\ & = y_0*cos( \beta) - z_0*sin( \beta)\\ \\ z_1 &= sin(\alpha + \beta)*R \\ & = sin(\alpha)cos( \beta) *R +cos(\alpha)sin( \beta)*R\\ & = y_0*sin( \beta) + z_0*cos( \beta)\\ \\ x_1 &= x_0 \end{aligned} \tag{2}
y1z1x1=cos(α+β)∗R=cos(α)cos(β)∗R−sin(α)sin(β)∗R=y0∗cos(β)−z0∗sin(β)=sin(α+β)∗R=sin(α)cos(β)∗R+cos(α)sin(β)∗R=y0∗sin(β)+z0∗cos(β)=x0(2)
我们可以得到绕
x
x
x轴旋转的矩阵:
M
r
x
=
(
1
0
0
0
0
c
o
s
(
β
)
−
s
i
n
(
β
)
0
0
s
i
n
(
β
)
c
o
s
(
β
)
0
0
0
0
1
)
M_{rx}= \begin{pmatrix} 1 & 0 & 0& 0\\ 0 & cos( \beta)& -sin( \beta)& 0\\ 0 & sin( \beta)& cos( \beta)& 0\\ 0 & 0& 0& 1\\ \end{pmatrix}
Mrx=
10000cos(β)sin(β)00−sin(β)cos(β)00001
下面是实现代码
static matrix4d rotationX(float angle)
{
matrix4d m;
T c = cos(angle);
T s = sin(angle);
m[5] = m[10] = c;
m[9] = -s;
m[6] = s;
return m;
}
注意,代码中的矩阵数组是列主序的
y y y轴
围绕
y
y
y轴的旋转和
x
x
x轴类似
只不过此时向右变成了
z
z
z轴,向上变成了
x
x
x轴
所以,我们直接上公式
z
1
=
z
0
∗
c
o
s
(
β
)
−
x
0
∗
s
i
n
(
β
)
x
1
=
z
0
∗
s
i
n
(
β
)
+
x
0
∗
c
o
s
(
β
)
y
1
=
y
0
\begin{aligned} z_1 & = z_0*cos( \beta) - x_0*sin( \beta)\\ \\ x_1 & = z_0*sin( \beta) + x_0*cos( \beta)\\ \\ y_1 &= y_0 \end{aligned}
z1x1y1=z0∗cos(β)−x0∗sin(β)=z0∗sin(β)+x0∗cos(β)=y0
M
r
y
=
(
c
o
s
(
β
)
0
s
i
n
(
β
)
0
0
1
0
0
−
s
i
n
(
β
)
0
c
o
s
(
β
)
0
0
0
0
1
)
M_{ry}= \begin{pmatrix} cos( \beta) & 0 & sin( \beta)& 0\\ 0 & 1& 0& 0\\ -sin( \beta) & 0& cos( \beta)& 0\\ 0 & 0& 0& 1\\ \end{pmatrix}
Mry=
cos(β)0−sin(β)00100sin(β)0cos(β)00001
下面是代码
static matrix4d rotationY(float angle)
{
matrix4d m;
T c = cos(angle);
T s = sin(angle);
m[0] = m[10] = c;
m[8] = s;
m[2] = -s;
return m;
}
注意,代码中的矩阵数组是列主序的
z z z轴
围绕
z
z
z轴的旋转和
x
x
x轴类似
只不过此时向右变成了
x
x
x轴,向上变成了
y
y
y轴
所以,我们直接上公式
x
1
=
x
0
∗
c
o
s
(
β
)
−
y
0
∗
s
i
n
(
β
)
y
1
=
x
0
∗
s
i
n
(
β
)
+
y
0
∗
c
o
s
(
β
)
z
1
=
y
0
\begin{aligned} x_1 & = x_0*cos( \beta) - y_0*sin( \beta)\\ \\ y_1 & = x_0*sin( \beta) + y_0*cos( \beta)\\ \\ z_1 &= y_0 \end{aligned}
x1y1z1=x0∗cos(β)−y0∗sin(β)=x0∗sin(β)+y0∗cos(β)=y0
M
r
z
=
(
c
o
s
(
β
)
−
s
i
n
(
β
)
0
0
s
i
n
(
β
)
c
o
s
(
β
)
0
0
0
0
1
0
0
0
0
1
)
M_{rz}= \begin{pmatrix} cos( \beta) & -sin( \beta) & 0& 0\\ sin( \beta) & cos( \beta)& 0& 0\\ 0& 0& 1& 0\\ 0 & 0& 0& 1\\ \end{pmatrix}
Mrz=
cos(β)sin(β)00−sin(β)cos(β)0000100001
下面是代码
static matrix4d rotationY(float angle)
{
matrix4d m;
T c = cos(angle);
T s = sin(angle);
m[0] = m[5] = c;
m[4] = -s;
m[1] = s;
return m;
}
注意,代码中的矩阵数组是列主序的
围绕任意轴的旋转
如果对象绕与每个坐标轴均不平行的轴旋转,则需要进行额外的变换。此时,还需要进行使旋转轴与某一选定坐标轴对齐的旋转,以后要将此轴变回到原始位置。若给定旋转轴和旋转角, 我们可以按照5个步骤来完成所需旋转:
- 平移对象,使得旋转轴通过坐标原点
- 旋转对象使得旋转轴与某一坐标轴重合
- 绕该坐标轴完成指定的旋转
- 利用逆旋转使旋转轴回到其原始方向
- 利用逆平移使旋转轴回到其原始位置
从之前我们在坐标轴进行旋转时,发现其实绕 z z z轴的旋转是最符合我们平时的认知的,因为向右是 x x x轴,向上是 y y y轴,这就是我们使用的二维坐标系,下面讨论使用 z z z轴旋转矩阵的变换序列
我们假设旋转轴由两个点确定,
P
1
P_1
P1和
P
2
P_2
P2,方向是从
P
1
P_1
P1到
P
2
P_2
P2,方向决定了旋转方向
P
1
=
(
x
1
,
y
1
,
z
1
)
P
2
=
(
x
2
,
y
2
,
z
2
)
P_1 = (x_1, y_1, z_1)\\ P_2 = (x_2, y_2, z_2)
P1=(x1,y1,z1)P2=(x2,y2,z2)
令
V
V
V为旋转轴的方向向量,则:
V
=
P
2
−
P
1
=
(
x
2
−
x
1
,
y
2
−
y
1
,
z
2
−
z
1
)
\begin{aligned} V & = P_2 - P_1\\ & = (x_2 - x_1,y_2 - y_1,z_2 - z_1) \end{aligned}
V=P2−P1=(x2−x1,y2−y1,z2−z1)
取
u
u
u为旋转轴单位方向向量,则:
u
=
V
∣
V
∣
=
(
a
,
b
,
c
)
u = \frac{V}{|V|} = (a,b,c)
u=∣V∣V=(a,b,c)
其中:
a
=
x
2
−
x
1
∣
V
∣
,
b
=
y
2
−
y
1
∣
V
∣
,
c
=
z
2
−
z
1
∣
V
∣
a = \frac{x_2 - x_1}{|V|}, \ \ b = \frac{y_2 - y_1}{|V|}, \ \ c = \frac{z_2 - z_1}{|V|}
a=∣V∣x2−x1, b=∣V∣y2−y1, c=∣V∣z2−z1
下面给出初始位置图:
平移到原点
我们把
P
1
P_1
P1平移到原点,下面是平移矩阵,平移后
P
2
P_2
P2也变成了
P
2
′
P_2^{'}
P2′
(
1
0
0
−
x
1
0
1
0
−
y
1
0
0
1
−
z
1
0
0
0
1
)
\begin{pmatrix} 1&0&0&-x_1\\ 0&1&0&-y_1\\ 0&0&1&-z_1\\ 0&0&0&1\\ \end{pmatrix}
100001000010−x1−y1−z11
将旋轴转旋转到z轴
将旋轴转旋转到 z z z轴的思路是:
- 先将旋转轴绕 x x x轴旋转到 x z xz xz平面
- 然后绕 y y y轴旋转到与 z z z轴重合
绕 x x x轴旋转到 x z xz xz平面
旋转角度为
α
\alpha
α
绕x轴的旋转矩阵我们上面已经介绍了,最重要的是要知道绕 x x x轴旋转到 x z xz xz平面的弧度的正弦余弦值
如果我们把
u
u
u投影到
y
z
yz
yz平面
u
′
u^{'}
u′,则
u
′
u^{'}
u′与
z
z
z轴正向的夹角即为
α
\alpha
α
我们前面已经获取到了
u
u
u的坐标,所以
c
o
s
(
α
)
=
c
d
,
d
=
b
2
+
c
2
s
i
n
(
α
)
=
b
d
,
d
=
b
2
+
c
2
cos(\alpha) = \frac{c}{d},\ \ d = \sqrt{b^2 + c^2}\\ sin(\alpha) = \frac{b}{d},\ \ d = \sqrt{b^2 + c^2}\\
cos(α)=dc, d=b2+c2sin(α)=db, d=b2+c2
此时我们可以获取到绕x轴旋转到
x
z
xz
xz平面的旋转矩阵了
R
x
=
(
1
0
0
0
0
c
d
−
b
d
0
0
b
d
c
d
0
0
0
0
1
)
R_x = \begin{pmatrix} 1&0&0&0\\ 0&\frac{c}{d}&-\frac{b}{d}&0\\ 0&\frac{b}{d}&\frac{c}{d}&0\\ 0&0&0&1\\ \end{pmatrix}
Rx=
10000dcdb00−dbdc00001
旋转后的
x
z
xz
xz平面的向量记为
u
′
′
u^{''}
u′′
绕 y y y轴旋转到 z z z轴
下一步需要确定变换矩阵,此矩阵将
x
x
x平面上的单位向量绕
y
y
y轴逆时针旋转到
z
z
z轴的正方向
绕
x
x
x轴旋转后,
x
x
x平面上单位向量的方向如下:
到目前为止,我们先理清 u ′ ′ u^{''} u′′的部分情况:
- 因为绕 x x x轴的旋转保持 x x x分量不变,故其 x x x分量值仍为 a a a
- 因为绕 x x x轴的旋转使 u ′ u^{'} u′旋转到了 z z z轴上,所以 u ′ ′ u^{''} u′′的 z z z分量为 d d d
- u ′ ′ u^{''} u′′的 y y y分量为0
根据上面的条件,我们可以得出
u
′
′
u^{''}
u′′旋转到
z
z
z轴正向的正弦余弦值
c
o
s
(
β
)
=
d
s
i
n
(
β
)
=
−
a
cos(\beta) = d\\ sin(\beta) = -a
cos(β)=dsin(β)=−a
所以,旋转矩阵为
R
y
=
(
d
0
−
a
0
0
1
0
0
a
0
d
0
0
0
0
1
)
R_y = \begin{pmatrix} d&0&-a&0\\ 0&1&0&0\\ a&0&d&0\\ 0&0&0&1\\ \end{pmatrix}
Ry=
d0a00100−a0d00001
绕 z z z轴旋转
直接给出旋转矩阵了:
R
z
=
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
0
0
s
i
n
(
θ
)
c
o
s
(
θ
)
0
0
0
0
1
0
0
0
0
1
)
R_z= \begin{pmatrix} cos( \theta) & -sin( \theta) & 0& 0\\ sin( \theta) & cos( \theta)& 0& 0\\ 0& 0& 1& 0\\ 0 & 0& 0& 1\\ \end{pmatrix}
Rz=
cos(θ)sin(θ)00−sin(θ)cos(θ)0000100001
最终的矩阵
到现在,很容易就能得出绕任意轴进行旋转的矩阵表示
R
(
θ
)
=
T
−
1
∗
R
x
(
α
)
∗
R
y
−
1
(
β
)
∗
R
z
(
θ
)
∗
R
y
(
β
)
∗
R
x
(
α
)
∗
T
R(\theta) = T^{-1}*R_x^{}(\alpha)*R_y^{-1}(\beta)*R_z(\theta)*R_y(\beta)*R_x(\alpha)*T
R(θ)=T−1∗Rx(α)∗Ry−1(β)∗Rz(θ)∗Ry(β)∗Rx(α)∗T