二维平移
我们可以使用二维列向量来表示平移和顶点位置
比如当前顶点坐标为:
P
=
(
x
y
)
P= \begin{pmatrix} x\\y \end{pmatrix}
P=(xy)
要平移的距离也用二维列向量来表示:
T
=
(
t
x
t
y
)
T= \begin{pmatrix} t_x\\t_y \end{pmatrix}
T=(txty)
那么,平移后的顶点坐标为:
P
′
=
(
x
′
y
′
)
=
(
x
y
)
+
(
t
x
t
y
)
=
P
+
T
P^{'}= \begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} x\\y \end{pmatrix}+ \begin{pmatrix} t_x\\t_y \end{pmatrix}= P+T
P′=(x′y′)=(xy)+(txty)=P+T
二维旋转
先考虑围绕原点进行的旋转
x
′
=
c
o
s
(
ϕ
+
θ
)
∗
r
=
c
o
s
(
ϕ
)
c
o
s
(
θ
)
∗
r
−
s
i
n
(
ϕ
)
s
i
n
(
θ
)
∗
r
=
x
∗
c
o
s
(
θ
)
−
y
∗
s
i
n
(
θ
)
y
′
=
s
i
n
(
ϕ
+
θ
)
∗
r
=
s
i
n
(
ϕ
)
c
o
s
(
θ
)
∗
r
+
c
o
s
(
ϕ
)
s
i
n
(
θ
)
∗
r
=
y
∗
c
o
s
(
θ
)
+
x
∗
s
i
n
(
θ
)
=
x
∗
s
i
n
(
θ
)
+
y
∗
c
o
s
(
θ
)
\begin{aligned} x^{'} &= cos(\phi+\theta)*r \\ &= cos(\phi)cos(\theta)*r - sin(\phi)sin(\theta)*r \\ &= x*cos(\theta) - y*sin(\theta)\\ \\ y^{'} &= sin(\phi+\theta)*r \\ &= sin(\phi)cos(\theta)*r + cos(\phi)sin(\theta)*r \\ &= y*cos(\theta) + x*sin(\theta)\\ &= x*sin(\theta) + y*cos(\theta) \end{aligned}
x′y′=cos(ϕ+θ)∗r=cos(ϕ)cos(θ)∗r−sin(ϕ)sin(θ)∗r=x∗cos(θ)−y∗sin(θ)=sin(ϕ+θ)∗r=sin(ϕ)cos(θ)∗r+cos(ϕ)sin(θ)∗r=y∗cos(θ)+x∗sin(θ)=x∗sin(θ)+y∗cos(θ)
所以,旋转后的坐标我们可以使用二维矩阵表示
P
′
=
(
x
′
y
′
)
=
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
s
i
n
(
θ
)
c
o
s
(
θ
)
)
(
x
y
)
=
R
∗
P
P^{'}= \begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} cos(\theta) & -sin(\theta)\\ sin(\theta) & cos(\theta) \end{pmatrix} \begin{pmatrix} x\\y \end{pmatrix}= R*P
P′=(x′y′)=(cos(θ)sin(θ)−sin(θ)cos(θ))(xy)=R∗P
其中:
R
=
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
s
i
n
(
θ
)
c
o
s
(
θ
)
)
,
θ
为旋转弧度
R= \begin{pmatrix} cos(\theta) & -sin(\theta)\\ sin(\theta) & cos(\theta) \end{pmatrix}, \theta为旋转弧度
R=(cos(θ)sin(θ)−sin(θ)cos(θ)),θ为旋转弧度
接下来,考虑围绕任意点
(
x
r
,
y
r
)
(x_r, y_r)
(xr,yr)的旋转。
思路是先把顶点移动
−
(
x
r
,
y
r
)
-(x_r, y_r)
−(xr,yr),变成围绕原点的旋转,旋转完成后在平移回去
x
′
=
(
x
−
x
r
)
∗
c
o
s
(
θ
)
−
(
y
−
y
r
)
∗
s
i
n
(
θ
)
+
x
r
y
′
=
(
x
−
x
r
)
∗
s
i
n
(
θ
)
+
(
y
−
y
r
)
∗
c
o
s
(
θ
)
+
y
r
x^{'} = (x-x_r)*cos(\theta) - (y-y_r)*sin(\theta) + x_r \\ y^{'} = (x-x_r)*sin(\theta) + (y-y_r)*cos(\theta) + y_r
x′=(x−xr)∗cos(θ)−(y−yr)∗sin(θ)+xry′=(x−xr)∗sin(θ)+(y−yr)∗cos(θ)+yr
使用矩阵表示为:
P
′
=
(
x
′
y
′
)
=
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
s
i
n
(
θ
)
c
o
s
(
θ
)
)
(
x
−
x
r
y
−
y
r
)
+
(
x
r
y
r
)
P^{'}= \begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} cos(\theta) & -sin(\theta)\\ sin(\theta) & cos(\theta) \end{pmatrix} \begin{pmatrix} x-x_r\\y-y_r \end{pmatrix}+ \begin{pmatrix} x_r\\y_r \end{pmatrix}
P′=(x′y′)=(cos(θ)sin(θ)−sin(θ)cos(θ))(x−xry−yr)+(xryr)
二维缩放
关于原点的缩放公式可以表示成
(
x
′
y
′
)
=
(
x
∗
s
x
y
∗
s
y
)
\begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} x*s_x\\y*s_y \end{pmatrix}
(x′y′)=(x∗sxy∗sy)
转换为矩阵表示为:
(
x
′
y
′
)
=
(
s
x
0
0
s
y
)
(
x
y
)
\begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} s_x&0\\0&s_y \end{pmatrix} \begin{pmatrix} x\\y \end{pmatrix}
(x′y′)=(sx00sy)(xy)
关于任意点的缩放和旋转一样,先把顶点移动
−
(
x
s
,
y
s
)
-(x_s, y_s)
−(xs,ys),变成围绕原点的缩放,缩放完成后在平移回去
(
x
′
y
′
)
=
(
s
x
0
0
s
y
)
(
x
−
x
s
y
−
x
s
)
+
(
x
s
y
s
)
\begin{pmatrix} x^{'}\\y^{'} \end{pmatrix}= \begin{pmatrix} s_x&0\\0&s_y \end{pmatrix} \begin{pmatrix} x-x_s\\y-x_s \end{pmatrix}+ \begin{pmatrix} x_s\\y_s \end{pmatrix}
(x′y′)=(sx00sy)(x−xsy−xs)+(xsys)
齐次坐标
通过上面的介绍,我们能看出来:
- 旋转和缩放可以表示成一个二维矩阵和顶点相乘的形式
- 平移操作可以表示成顶点和一个矩阵或者向量相加操作
即
P
′
=
M
1
∗
P
+
M
2
P^{'} = M_1*P + M_2
P′=M1∗P+M2
对于平移,
M
1
M_1
M1是单位矩阵
对于旋转或者缩放,
M
2
M_2
M2包含基准点或者缩放固定点的平移项
现在考虑一种多个变换操作:
- 缩放
- 旋转
- 平移
我们只能一步一步进行,因为公式中包含矩阵的加法,而如果只有矩阵的乘法的话,多个操作就可以合并成一个操作了,相当于
P
′
=
M
t
∗
M
r
∗
M
s
∗
P
P^{'} = M_t*M_r*M_s*P
P′=Mt∗Mr∗Ms∗P
这就是齐次坐标引入的原因
我们将2x2的矩阵表达式扩充为3x3矩阵,就可以把二维几何变换的乘法和平移项组合成单一矩阵表示。这时将变换矩阵的第三列用于平移项,而所有的变换公式可表达为矩阵乘法
接下来,我们用齐次坐标重新表示一下二维的平移,旋转和缩放
平移
P ′ = ( x ′ y ′ 1 ) = ( 1 0 t x 0 1 t y 0 0 1 ) ( x y 1 ) = M t P P^{'}= \begin{pmatrix} x^{'}\\y^{'}\\1 \end{pmatrix}= \begin{pmatrix} 1&0&t_x\\ 0&1&t_y\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x\\y\\1 \end{pmatrix}= M_tP P′= x′y′1 = 100010txty1 xy1 =MtP
旋转
P ′ = ( x ′ y ′ 1 ) = ( c o s ( θ ) − s i n ( θ ) 0 s i n ( θ ) c o s ( θ ) 0 0 0 1 ) ( x y 1 ) = M r P P^{'}= \begin{pmatrix} x^{'}\\y^{'}\\1 \end{pmatrix}= \begin{pmatrix} cos(\theta)&-sin(\theta)&0\\ sin(\theta)&cos(\theta)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x\\y\\1 \end{pmatrix}= M_rP P′= x′y′1 = cos(θ)sin(θ)0−sin(θ)cos(θ)0001 xy1 =MrP
缩放
P
′
=
(
x
′
y
′
1
)
=
(
s
x
0
0
0
s
y
0
0
0
1
)
(
x
y
1
)
=
M
s
P
P^{'}= \begin{pmatrix} x^{'}\\y^{'}\\1 \end{pmatrix}= \begin{pmatrix} s_x&0&0\\ 0&s_y&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x\\y\\1 \end{pmatrix}= M_sP
P′=
x′y′1
=
sx000sy0001
xy1
=MsP
M
t
、
M
r
、
M
s
M_t、M_r、M_s
Mt、Mr、Ms即为三种变换的变换矩阵
逆变换
M
t
、
M
r
、
M
s
M_t、M_r、M_s
Mt、Mr、Ms的逆变换分别表示为
M
t
′
、
M
r
′
、
M
s
′
M_t^{'}、M_r^{'}、M_s^{'}
Mt′、Mr′、Ms′
M
t
′
=
(
1
0
−
t
x
0
1
−
t
y
0
0
1
)
M_t^{'} = \begin{pmatrix} 1&0&-t_x\\ 0&1&-t_y\\ 0&0&1 \end{pmatrix}
Mt′=
100010−tx−ty1
M r ′ = ( c o s ( θ ) s i n ( θ ) 0 − s i n ( θ ) c o s ( θ ) 0 0 0 1 ) M_r^{'} = \begin{pmatrix} cos(\theta)&sin(\theta)&0\\ -sin(\theta)&cos(\theta)&0\\ 0&0&1 \end{pmatrix} Mr′= cos(θ)−sin(θ)0sin(θ)cos(θ)0001
M s ′ = ( 1 s x 0 0 0 1 s y 0 0 0 1 ) M_s^{'} = \begin{pmatrix} \frac{1}{s_x}&0&0\\ 0&\frac{1}{s_y}&0\\ 0&0&1 \end{pmatrix} Ms′= sx1000sy10001
复合变换
复合变换有以下几种方式:
- 多个平移变换
- 多个旋转变换
- 多个缩放变换
- 基于给顶点的旋转
- 基于给顶点的缩放
-上述项的混合
多个平移变换和多个缩放变换很好理解,不过多解释
多个平移变换就是多个平移项相加
多个缩放变换就是多个缩放因子相乘
多个旋转变换
比如两次旋转弧度分别为
θ
1
\theta_1
θ1和
θ
2
\theta_2
θ2
旋转矩阵可以表示为
M
r
=
(
c
o
s
(
θ
1
)
s
i
n
(
θ
1
)
0
−
s
i
n
(
θ
1
)
c
o
s
(
θ
1
)
0
0
0
1
)
(
c
o
s
(
θ
2
)
s
i
n
(
θ
2
)
0
−
s
i
n
(
θ
2
)
c
o
s
(
θ
2
)
0
0
0
1
)
=
(
c
o
s
(
θ
1
)
c
o
s
(
θ
2
)
−
s
i
n
(
θ
1
)
s
i
n
(
θ
2
)
c
o
s
(
θ
1
)
s
i
n
(
θ
2
)
+
s
i
n
(
θ
1
)
c
o
s
(
θ
2
)
0
−
s
i
n
(
θ
1
)
c
o
s
(
θ
2
)
−
c
o
s
(
θ
1
)
s
i
n
(
θ
2
)
−
s
i
n
(
θ
1
)
s
i
n
(
θ
2
)
+
c
o
s
(
θ
1
)
c
o
s
(
θ
2
)
0
0
0
1
)
=
(
c
o
s
(
θ
1
+
θ
2
)
s
i
n
(
θ
1
+
θ
2
)
0
−
s
i
n
(
θ
1
+
θ
2
)
c
o
s
(
θ
1
+
θ
2
)
0
0
0
1
)
\begin{aligned} M_r &= \begin{pmatrix} cos(\theta_1)&sin(\theta_1)&0\\ -sin(\theta_1)&cos(\theta_1)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} cos(\theta_2)&sin(\theta_2)&0\\ -sin(\theta_2)&cos(\theta_2)&0\\ 0&0&1 \end{pmatrix}\\ &= \begin{pmatrix} cos(\theta_1)cos(\theta_2)-sin(\theta_1)sin(\theta_2)&cos(\theta_1)sin(\theta_2)+sin(\theta_1)cos(\theta_2)&0\\ -sin(\theta_1)cos(\theta_2)-cos(\theta_1)sin(\theta_2)&-sin(\theta_1)sin(\theta_2)+cos(\theta_1)cos(\theta_2)&0\\ 0&0&1 \end{pmatrix}\\ &= \begin{pmatrix} cos(\theta_1+\theta_2)&sin(\theta_1+\theta_2)&0\\ -sin(\theta_1+\theta_2)&cos(\theta_1+\theta_2)&0\\ 0&0&1 \end{pmatrix} \end{aligned}
Mr=
cos(θ1)−sin(θ1)0sin(θ1)cos(θ1)0001
cos(θ2)−sin(θ2)0sin(θ2)cos(θ2)0001
=
cos(θ1)cos(θ2)−sin(θ1)sin(θ2)−sin(θ1)cos(θ2)−cos(θ1)sin(θ2)0cos(θ1)sin(θ2)+sin(θ1)cos(θ2)−sin(θ1)sin(θ2)+cos(θ1)cos(θ2)0001
=
cos(θ1+θ2)−sin(θ1+θ2)0sin(θ1+θ2)cos(θ1+θ2)0001
也就是说两次旋转相当于两个旋转弧度相加后进行一次旋转
基于给顶点的旋转和缩放
基于给定点的旋转和缩放其实本质如下:
- 进行平移逆变换,平移量就是基准点的坐标
- 进行缩放或者旋转
- 进行平移变换,平移量是基准点的坐标
即
P
′
=
M
t
∗
M
r
∗
M
t
′
∗
P
P
′
=
M
t
∗
M
s
∗
M
t
′
∗
P
P^{'} = M_t * M_r * M_t^{'}*P \\ P^{'} = M_t * M_s * M_t^{'}*P
P′=Mt∗Mr∗Mt′∗PP′=Mt∗Ms∗Mt′∗P
基于定向的缩放
基于定向的缩放的就是缩放因子不是基于当前x轴和y轴的,而是基于任意方向。
上面图的缩放因子就是基于x轴方向 ( 1 , 1 ) (1,1) (1,1)和y轴方向 ( − 1 , 1 ) (-1,1) (−1,1)的
怎么表示基于定向的缩放呢,其实也是一种混合变换,变换过程如下:
- 先判断缩放坐标轴与当前坐标系的角度,记为 θ \theta θ,上图为 π 4 \frac{\pi}{4} 4π
- 构造旋转 − θ -\theta −θ的旋转矩阵,使定向坐标轴与当前坐标轴对齐
- 然后进行缩放
- 然后旋转 θ \theta θ
即
P
′
=
M
r
∗
M
s
∗
M
r
′
∗
P
P^{'} = M_r * M_s * M_r^{'} *P
P′=Mr∗Ms∗Mr′∗P
二维坐标系的变换
坐标系变换在游戏引擎或者计算机图形中是经常使用的。
对于一个二维游戏来说,游戏对象树的一个子节点的位置,方向,缩放一般都是相对于父节点的,但是我们在进行顶点坐标计算的时候需要知道相对于世界坐标系的位置。
所以需要进行坐标系的转换
其实二维坐标系的变换知识点上面都已经介绍了,我们看一下图中的例子:
- x O y xOy xOy坐标系是世界坐标系
- x ′ O ′ y ′ x^{'}O^{'}y^{'} x′O′y′坐标系是节点 N N N的局部坐标系, N N N的位置为 ( x N , y N ) (x_N,y_N) (xN,yN),旋转弧度为 θ \theta θ
- 节点 n n n是节点 N N N的子节点, n n n的位置为 ( x n , y n ) (x_n,y_n) (xn,yn),旋转弧度为 θ 1 \theta_1 θ1
对于节点
n
n
n中的一个顶点
v
(
x
,
y
)
v(x,y)
v(x,y),我们可以求出在
x
′
O
′
y
′
x^{'}O^{'}y^{'}
x′O′y′的坐标
v
N
=
(
x
N
y
N
1
)
=
(
1
0
x
n
0
1
y
n
0
0
1
)
(
c
o
s
(
θ
1
)
−
s
i
n
(
θ
1
)
0
s
i
n
(
θ
1
)
c
o
s
(
θ
1
)
0
0
0
1
)
(
x
y
1
)
v_N= \begin{pmatrix} x_N\\y_N\\1 \end{pmatrix}= \begin{pmatrix} 1&0&x_n\\ 0&1&y_n\\ 0&0&1 \end{pmatrix} \begin{pmatrix} cos(\theta_1)&-sin(\theta_1)&0\\ sin(\theta_1)&cos(\theta_1)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x\\y\\1 \end{pmatrix}
vN=
xNyN1
=
100010xnyn1
cos(θ1)sin(θ1)0−sin(θ1)cos(θ1)0001
xy1
同理,可以求出
v
N
v_N
vN在
x
O
y
xOy
xOy坐标系的坐标
v
1
=
(
x
1
y
1
1
)
=
(
1
0
x
N
0
1
y
N
0
0
1
)
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
0
s
i
n
(
θ
)
c
o
s
(
θ
)
0
0
0
1
)
(
x
N
y
N
1
)
=
(
1
0
x
N
0
1
y
N
0
0
1
)
(
c
o
s
(
θ
)
−
s
i
n
(
θ
)
0
s
i
n
(
θ
)
c
o
s
(
θ
)
0
0
0
1
)
(
1
0
x
n
0
1
y
n
0
0
1
)
(
c
o
s
(
θ
1
)
−
s
i
n
(
θ
1
)
0
s
i
n
(
θ
1
)
c
o
s
(
θ
1
)
0
0
0
1
)
(
x
y
1
)
\begin{aligned} v_1&= \begin{pmatrix} x_1\\y_1\\1 \end{pmatrix}= \begin{pmatrix} 1&0&x_N\\ 0&1&y_N\\ 0&0&1 \end{pmatrix} \begin{pmatrix} cos(\theta)&-sin(\theta)&0\\ sin(\theta)&cos(\theta)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x_N\\y_N\\1 \end{pmatrix} \\\\ &= \begin{pmatrix} 1&0&x_N\\ 0&1&y_N\\ 0&0&1 \end{pmatrix} \begin{pmatrix} cos(\theta)&-sin(\theta)&0\\ sin(\theta)&cos(\theta)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} 1&0&x_n\\ 0&1&y_n\\ 0&0&1 \end{pmatrix} \begin{pmatrix} cos(\theta_1)&-sin(\theta_1)&0\\ sin(\theta_1)&cos(\theta_1)&0\\ 0&0&1 \end{pmatrix} \begin{pmatrix} x\\y\\1 \end{pmatrix} \end{aligned}
v1=
x1y11
=
100010xNyN1
cos(θ)sin(θ)0−sin(θ)cos(θ)0001
xNyN1
=
100010xNyN1
cos(θ)sin(θ)0−sin(θ)cos(θ)0001
100010xnyn1
cos(θ1)sin(θ1)0−sin(θ1)cos(θ1)0001
xy1
所以,我们可以总结出,子节点到父节点的坐标系转换矩阵就是
子节点的平移矩阵\*子节点的旋转矩阵\*子节点的缩放矩阵
当然,父节点到子节点的坐标系转换矩阵是上述矩阵的逆矩阵