1 简介
计算机图形学中的应用非常广泛的变换是一种称为仿射变换的特殊变换,在仿射变换中的基本变换包括平移、旋转、缩放、剪切这几种。本文以及接下来的几篇文章重点介绍一下关于旋转的变换,包括二维旋转变换、三维旋转变换以及它的一些表达方式(旋转矩阵、四元数、欧拉角等)。
2 绕原点二维旋转
首先要明确旋转在二维中是绕着某一个点进行旋转,三维中是绕着某一个轴进行旋转。二维旋转中最简单的场景是绕着坐标原点进行的旋转,如下图所示:
如图所示点v 绕 原点旋转θ 角,得到点v’,假设 v点的坐标是(x, y) ,那么可以推导得到 v’点的坐标(x’, y’)(设原点到v的距离是r,原点到v点的向量与x轴的夹角是ϕ )
x=rcosϕ
y=rsinϕ
x′=rcos(θ+ϕ)
y′=rsin(θ+ϕ)
通过三角函数展开得到
x′=rcosθcosϕ−rsinθsinϕ
y′=rsinθcosϕ+rcosθsinϕ
带入x和y表达式得到
x′=xcosθ−ysinθ
y′=xsinθ+ycosθ
写成矩阵的形式是:
[
cos
(
θ
)
−
sin
(
θ
)
sin
(
θ
)
cos
(
θ
)
]
\begin{bmatrix} \cos(\theta)&-\sin(\theta)\\ \sin(\theta)&\cos(\theta) \end{bmatrix}
[cos(θ)sin(θ)−sin(θ)cos(θ)]
尽管图示中仅仅表示的是旋转一个锐角θ的情形,但是我们推导中使用的是三角函数的基本定义来计算坐标的,因此当旋转的角度是任意角度(例如大于180度,导致v’点进入到第四象限)结论仍然是成立的。
3 绕任意点的二维旋转
绕原点的旋转是二维旋转最基本的情况,当我们需要进行绕任意点旋转时,我们可以把这种情况转换到绕原点的旋转,思路如下:
- 首先将旋转点移动到原点处
- 执行如2所描述的绕原点的旋转
- 再将旋转点移回到原来的位置
也就是说在处理绕任意点旋转的情况下需要执行两次平移的操作。假设平移的矩阵是T(x,y),也就是说我们需要得到的坐标 v’=T(x,y)RT(-x,-y)(我们使用的是列坐标描述点的坐标,因此是左乘,首先执行T(-x,-y))
在计算机图形学中,为了统一将平移、旋转、缩放等用矩阵表示,需要引入齐次坐标。(假设使用2x2的矩阵,是没有办法描述平移操作的,只有引入3x3矩阵形式,才能统一描述二维中的平移、旋转、缩放操作。同理必须使用4x4的矩阵才能统一描述三维的变换)。
对于二维平移,如下图所示,P点经过x和y方向的平移到P’点,可以得到:
{
x
′
=
x
+
t
x
y
′
=
y
+
t
y
\left\{\begin{aligned}x^\prime=x+t_x\\ y^\prime=y+t_y\end{aligned}\right.
{x′=x+txy′=y+ty
由于引入了齐次坐标,在描述二维坐标的时候,使用(x,y,w)的方式(一般w=1),于是可以写成下面矩阵的形式
[
x
′
y
′
1
]
=
[
1
0
t
x
0
1
t
y
0
0
1
]
⋅
[
x
y
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} 1&0&t_x\\ 0&1&t_y\\ 0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}
⎣⎡x′y′1⎦⎤=⎣⎡100010txty1⎦⎤⋅⎣⎡xy1⎦⎤
按矩阵乘法展开,正好得到上面的表达式。也就是说平移矩阵是
[
1
0
t
x
0
1
t
y
0
0
1
]
\begin{bmatrix} 1&0&t_x\\ 0&1&t_y\\ 0&0&1 \end{bmatrix}
⎣⎡100010txty1⎦⎤
如果平移值是
(
−
t
x
,
−
t
y
)
(-t_x,-t_y)
(−tx,−ty) 那么很明显平移矩阵式
[
1
0
−
t
x
0
1
−
t
y
0
0
1
]
\begin{bmatrix} 1&0&-t_x\\ 0&1&-t_y\\ 0&0&1 \end{bmatrix}
⎣⎡100010−tx−ty1⎦⎤
我们可以把2中描述的旋转矩阵也扩展到3x3的方式,变为:
[
x
′
y
′
1
]
=
[
cos
(
θ
)
−
sin
(
θ
)
0
sin
(
θ
)
cos
(
θ
)
0
0
0
1
]
⋅
[
x
y
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} \cos(\theta)&-\sin(\theta)&0\\ \sin(\theta)&\cos(\theta)&0\\ 0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}
⎣⎡x′y′1⎦⎤=⎣⎡cos(θ)sin(θ)0−sin(θ)cos(θ)0001⎦⎤⋅⎣⎡xy1⎦⎤
从平移和旋转的矩阵可以看出,3x3矩阵的前2x2部分是和旋转相关的,第三列与平移相关。有了上面的基础之后,我们很容易得出二维中绕任意点旋转的旋转矩阵了,只需要把三个矩阵乘起来即可:
[
x
′
y
′
1
]
=
[
1
0
t
x
0
1
t
y
0
0
1
]
⋅
[
cos
(
θ
)
−
sin
(
θ
)
0
sin
(
θ
)
cos
(
θ
)
0
0
0
1
]
⋅
[
1
0
−
t
x
0
1
−
t
y
0
0
1
]
⋅
[
x
y
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} 1&0&t_x\\ 0&1&t_y\\ 0&0&1 \end{bmatrix}\cdot \begin{bmatrix} \cos(\theta)&-\sin(\theta)&0\\ \sin(\theta)&\cos(\theta)&0\\ 0&0&1 \end{bmatrix}\cdot \begin{bmatrix} 1&0&-t_x\\ 0&1&-t_y\\ 0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}
⎣⎡x′y′1⎦⎤=⎣⎡100010txty1⎦⎤⋅⎣⎡cos(θ)sin(θ)0−sin(θ)cos(θ)0001⎦⎤⋅⎣⎡100010−tx−ty1⎦⎤⋅⎣⎡xy1⎦⎤
4 三维基本旋转
我们可以把一个旋转转换为绕基本坐标轴的旋转,因此有必要讨论一下绕三个坐标值x、y、z的旋转。
本文在讨论过程中使用的是类似于OpenGL中定义的右手坐标系,同时旋转角度的正负也遵循右手坐标系的约定。如下图所示
4.1 绕X轴的旋转
在三维场景中,当一个点P(x,y,z)绕x轴旋转θ角得到点P’(x’,y’,z’)。由于是绕x轴进行的旋转,因此x坐标保持不变,y和z组成的yoz(o是坐标原点)平面上进行的是一个二维的旋转,可以参考上图(y轴类似于二维旋转中的x轴,z轴类似于二维旋转中的y轴),于是有:
x′=x
y′=ycosθ−zsinθ
z′=ysinθ+zcosθ
写成(4x4)矩阵的形式
[
x
′
y
′
z
′
1
]
=
[
1
0
0
0
0
cos
(
θ
)
−
sin
(
θ
)
0
0
sin
(
θ
)
cos
(
θ
)
0
0
0
0
1
]
⋅
[
x
y
z
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ z^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} 1&0&0&0\\ 0&\cos(\theta)&-\sin(\theta)&0\\ 0&\sin(\theta)&\cos(\theta)&0\\ 0&0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}
⎣⎢⎢⎡x′y′z′1⎦⎥⎥⎤=⎣⎢⎢⎡10000cos(θ)sin(θ)00−sin(θ)cos(θ)00001⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤
4.2 绕Y轴旋转
绕Y轴的旋转和绕X轴的旋转类似,Y坐标保持不变,除Y轴之外,ZOX组成的平面进行一次二维的旋转(Z轴类似于二维旋转的X轴,X轴类似于二维旋转中的Y轴,注意这里是ZOX,而不是XOZ,观察上图中右手系的图片可以很容易了解到这一点),同样有:
x′=zsinθ+xcosθ
y′=y
z′=zcosθ−xsinθ
写成(4x4)矩阵的形式
[
x
′
y
′
z
′
1
]
=
[
cos
(
θ
)
0
sin
(
θ
)
0
0
1
0
0
−
sin
(
θ
)
0
cos
(
θ
)
0
0
0
0
1
]
⋅
[
x
y
z
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ z^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} \cos(\theta)&0&\sin(\theta)&0\\ 0&1&0&0\\ -\sin(\theta)&0&\cos(\theta)&0\\ 0&0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}
⎣⎢⎢⎡x′y′z′1⎦⎥⎥⎤=⎣⎢⎢⎡cos(θ)0−sin(θ)00100sin(θ)0cos(θ)00001⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤
4.3 绕Z轴旋转
与上面类似,绕Z轴旋转,Z坐标保持不变,xoy组成的平面内正好进行一次二维旋转(和上面讨论二维旋转的情况完全一样)
[
x
′
y
′
z
′
1
]
=
[
cos
(
θ
)
−
sin
(
θ
)
0
0
sin
(
θ
)
cos
(
θ
)
0
0
0
0
1
0
0
0
0
1
]
⋅
[
x
y
z
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ z^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} \cos(\theta)&-\sin(\theta)&0&0\\ \sin(\theta)&\cos(\theta)&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}
⎣⎢⎢⎡x′y′z′1⎦⎥⎥⎤=⎣⎢⎢⎡cos(θ)sin(θ)00−sin(θ)cos(θ)0000100001⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤
4.4 小结
上面描述了三维变换中绕单一轴旋转的矩阵表达形式,绕三个轴旋转的矩阵很类似,其中绕y轴旋转的矩阵与绕x和z轴旋转的矩阵略有点不同(主要是三个轴向顺序和书写矩阵的方式不一致导致的,绕三个不同坐标旋转轴以及其他二个坐标轴组成平面的顺序是: XYZ(绕x轴) YZX(绕y轴) ZXY(绕z轴),其中绕y轴旋转,其他两个轴是ZX,这和我们书写矩阵按
[
x
′
y
′
z
′
1
]
\begin{bmatrix} x^\prime\\ y^\prime\\ z^\prime\\ 1 \end{bmatrix}
⎣⎢⎢⎡x′y′z′1⎦⎥⎥⎤
的方式不一致,而导致看起来绕Y轴旋转的矩阵似乎是和其他两个矩阵不一致。如果我们颠倒写法,将公式写成
[
z
′
y
′
x
′
1
]
=
[
cos
(
θ
)
0
−
sin
(
θ
)
0
0
1
0
0
sin
(
θ
)
0
cos
(
θ
)
0
0
0
0
1
]
⋅
[
x
y
z
1
]
\begin{bmatrix} z^\prime\\ y^\prime\\ x^\prime\\ 1 \end{bmatrix}= \begin{bmatrix} \cos(\theta)&0&-\sin(\theta)&0\\ 0&1&0&0\\ \sin(\theta)&0&\cos(\theta)&0\\ 0&0&0&1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}
⎣⎢⎢⎡z′y′x′1⎦⎥⎥⎤=⎣⎢⎢⎡cos(θ)0sin(θ)00100−sin(θ)0cos(θ)00001⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤
的方式,那么这三个旋转矩阵看起来在形式上就统一了,都是
[
cos
(
θ
)
−
sin
(
θ
)
sin
(
θ
)
cos
(
θ
)
]
\begin{bmatrix} \cos(\theta)&-\sin(\theta)\\ \sin(\theta)&\cos(\theta) \end{bmatrix}
[cos(θ)sin(θ)−sin(θ)cos(θ)]
这种表现形式了(左上角都是−sinθ)
5. 绕任意轴的三维旋转
绕任意轴旋转的情况比较复杂,主要分为两种情况,一种是平行于坐标轴的,一种是不平行于坐标轴的。
5.1 平行于坐标轴的
对于平行于坐标轴的,我们首先将旋转轴平移至与坐标轴重合,然后进行旋转,最后再平移回去。
- 将旋转轴平移至与坐标轴重合,对应平移操作 T
- 旋转,对应操作 R
- 步骤1的逆过程,对应操作 T
整个过程就是: P ′ = P ⋅ T ⋅ R ⋅ T − 1 P^\prime=P\cdot T\cdot R\cdot T^{-1} P′=P⋅T⋅R⋅T−1
5.1 不平行于坐标轴的
- 将旋转轴平移至原点
- 将旋转轴旋转至YOZ平面
- 将旋转轴旋转至于Z轴重合
- 绕Z轴旋转θ度
- 执行步骤3的逆过程
- 执行步骤2的逆过程
- 执行步骤1的逆过程
假设用v1(a1, b2, c2)和v2(a2, b2, c2)来表示旋转轴,θ表示旋转角度。为了方便推导,暂时使用右手系并使用列向量,待得出矩阵后转置一下即可,上面第1、2、3步骤对应的流程图如下:
步骤1是一个平移操作,将v1v2平移至原点,对应的矩阵为:
T
(
x
,
y
,
z
)
=
[
1
0
0
−
a
1
0
1
0
−
b
1
0
0
1
−
c
1
0
0
0
1
]
T(x,y,z)=\begin{bmatrix} 1&0&0&-a_1\\ 0&1&0&-b_1\\ 0&0&1&-c_1\\ 0&0&0&1 \end{bmatrix}
T(x,y,z)=⎣⎢⎢⎡100001000010−a1−b1−c11⎦⎥⎥⎤
步骤2是一个旋转操作,将 P 旋转至XOZ平面,步骤3也是一个旋转操作,将p旋转至与Z轴重合,这两个操作对应的图如下:
做点p在平面YOZ上的投影点q。再过q做Z轴垂线,则r是p绕X轴旋转所得,且旋转角度为α,且
cos
α
=
c
b
2
+
c
2
sin
α
=
b
b
2
+
c
2
\cos\alpha=\frac{c}{\sqrt{b^2+c^2}}\quad\sin\alpha=\frac{b}{\sqrt{b^2+c^2}}
cosα=b2+c2
csinα=b2+c2
b
于是绕X轴旋转矩阵为:
[
1
0
0
0
0
c
b
2
+
c
2
−
b
b
2
+
c
2
0
0
b
b
2
+
c
2
c
b
2
+
c
2
0
0
0
0
1
]
\begin{bmatrix} 1&0&0&0\\ 0&\frac{c}{\sqrt{b^2+c^2}}&-\frac{b}{\sqrt{b^2+c^2}}&0\\ 0&\frac{b}{\sqrt{b^2+c^2}}&\frac{c}{\sqrt{b^2+c^2}}&0\\ 0&0&0&1 \end{bmatrix}
⎣⎢⎢⎡10000b2+c2
cb2+c2
b00−b2+c2
bb2+c2
c00001⎦⎥⎥⎤
现在将r绕Y轴旋转至与Z轴重合,旋转的角度为
−
β
-\beta
−β(方向为顺时针),且
cos
(
−
β
)
=
cos
(
β
)
=
b
2
+
c
2
a
2
+
b
2
+
c
2
sin
(
−
β
)
=
−
sin
(
β
)
=
−
a
a
2
+
b
2
+
c
2
\cos(-\beta)=\cos(\beta)=\frac{\sqrt{b^2+c^2}}{\sqrt{a^2+b^2+c^2}}\quad \sin(-\beta)=-\sin(\beta)=-\frac{a}{\sqrt{a^2+b^2+c^2}}
cos(−β)=cos(β)=a2+b2+c2
b2+c2
sin(−β)=−sin(β)=−a2+b2+c2
a
绕Z轴旋转矩阵为:
[
cos
(
−
β
)
0
sin
(
−
β
)
0
0
1
0
0
−
sin
(
−
β
)
0
cos
(
−
β
)
0
0
0
0
1
]
=
[
b
2
+
c
2
a
2
+
b
2
+
c
2
0
−
a
a
2
+
b
2
+
c
2
0
0
1
0
0
a
a
2
+
b
2
+
c
2
0
b
2
+
c
2
a
2
+
b
2
+
c
2
0
0
0
0
1
]
\begin{bmatrix} \cos(-\beta)&0&\sin(-\beta)&0\\ 0&1&0&0\\ -\sin(-\beta)&0&\cos(-\beta)&0\\ 0&0&0&1 \end{bmatrix}= \begin{bmatrix} \frac{\sqrt{b^2+c^2}}{\sqrt{a^2+b^2+c^2}}&0&-\frac{a}{\sqrt{a^2+b^2+c^2}}&0\\ 0&1&0&0\\ \frac{a}{\sqrt{a^2+b^2+c^2}}&0&\frac{\sqrt{b^2+c^2}}{\sqrt{a^2+b^2+c^2}}&0\\ 0&0&0&1 \end{bmatrix}
⎣⎢⎢⎡cos(−β)0−sin(−β)00100sin(−β)0cos(−β)00001⎦⎥⎥⎤=⎣⎢⎢⎢⎡a2+b2+c2
b2+c2
0a2+b2+c2
a00100−a2+b2+c2
a0a2+b2+c2
b2+c2
00001⎦⎥⎥⎥⎤
最后是绕Z轴旋转,对应的矩阵如下:
[
cos
(
θ
)
−
sin
(
θ
)
0
0
sin
(
θ
)
cos
(
θ
)
0
0
0
0
1
0
0
0
0
1
]
\begin{bmatrix} \cos(\theta)&-\sin(\theta)&0&0\\ \sin(\theta)&\cos(\theta)&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix}
⎣⎢⎢⎡cos(θ)sin(θ)00−sin(θ)cos(θ)0000100001⎦⎥⎥⎤
如果旋转轴是过原点的,那么第一步和最后一步的平移操作可以省略,也就是把中间五个矩阵连乘起来,再转置一下,得到下面的绕任意轴旋转的矩阵:
M
=
R
x
(
−
α
)
⋅
R
y
(
β
)
⋅
R
z
(
θ
)
⋅
R
y
(
−
β
)
⋅
R
x
(
α
)
M=R_x(-\alpha)\cdot R_y(\beta)\cdot R_z(\theta)\cdot R_y(-\beta)\cdot R_x(\alpha)
M=Rx(−α)⋅Ry(β)⋅Rz(θ)⋅Ry(−β)⋅Rx(α)
即: