坐标变换(平移、旋转与缩放)

本文主要参考Coordinate Systems and Transformations(坐标系及其变换)


主要内容

  1. 坐标系与广义坐标系
  2. 坐标变换
  3. 仿射变换
  4. 旋转、平移、伸缩与剪切
  5. 绕任意轴旋转

注:Coordinate systems and frames,本文译为坐标系与广义坐标系。


一、坐标系与广义坐标系

1.1 坐标系旋转变换

向量 v ∈ R 3 v \in R^3 vR3 可以用一组基向量 v 1 , v 2 , v 3 v_1, v_2, v_3 v1,v2,v3的线性组合表示,

v = α 1 v 1 + α 2 v 2 + α 3 v 3 v = \alpha_1 v_1 + \alpha_2 v_2 + \alpha_3 v_3 v=α1v1+α2v2+α3v3

其中,标量 α 1 , α 2 , α 3 \alpha_1, \alpha_2, \alpha_3 α1,α2,α3 v v v的坐标(coordinates)。一般地,我们可以选择 v 1 = ( 1 , 0 , 0 ) , v 2 = ( 0 , 1 , 0 ) , v 3 = ( 0 , 0 , 1 ) v_1=(1,0,0), v_2=(0,1,0), v_3=(0,0,1) v1=(1,0,0),v2=(0,1,0),v3=(0,0,1)

假设我们想要将一组基向量 v 1 , v 2 , v 3 v_1, v_2, v_3 v1,v2,v3转换为另一组基向量 u 1 , u 2 , u 3 u_1, u_2, u_3 u1,u2,u3,我们可以将新的基向量表示为原始基向量的线性组合,

u 1 = a 11 v 1 + a 12 v 2 + a 13 v 3 u 2 = a 21 v 1 + a 22 v 2 + a 23 v 3 u 3 = a 31 v 1 + a 32 v 2 + a 33 v 3 u_1 = a_{11}v_1 + a_{12} v_2 + a_{13} v_3 \\ u_2 = a_{21}v_1 + a_{22} v_2 + a_{23} v_3 \\ u_3 = a_{31}v_1 + a_{32} v_2 + a_{33} v_3 \\ u1=a11v1+a12v2+a13v3u2=a21v1+a22v2+a23v3u3=a31v1+a32v2+a33v3

由此则可得到一个 3 × 3 3\times3 3×3的“基变换”矩阵

M = ( a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 ) M = \left ( \begin {array}{cc} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{array}\right ) M=a11a21a31a12a22a32a13a23a33

如果对于一个给定向量 v v v,在两个坐标系下的表示分别为

v = a T ( v 1 v 2 v 3 ) v = b T ( u 1 u 2 u 3 ) v = \bm a^T \left ( \begin{array}{c} v_1 \\ v_2 \\ v_3 \end{array}\right ) \qquad\qquad v = \bm b^T \left ( \begin{array}{c} u_1 \\ u_2 \\ u_3 \end{array}\right ) v=aTv1v2v3v=bTu1u2u3

其中, a = ( α 1 , α 2 , α 3 ) T \bm a=(\alpha_1, \alpha_2, \alpha_3)^T a=(α1,α2,α3)T b = ( β 1 , β 2 , β 3 ) T \bm b = (\beta_1, \beta_2, \beta_3)^T b=(β1,β2,β3)T,那么

a T ( v 1 v 2 v 3 ) = v = b T ( u 1 u 2 u 3 ) = b T M ( v 1 v 2 v 3 ) \bm a^T \left ( \begin{array}{c} v_1 \\ v_2 \\ v_3 \end{array}\right ) = v = \bm b^T \left ( \begin{array}{c} u_1 \\ u_2 \\ u_3 \end{array}\right ) = \bm b^T M \left ( \begin{array}{c} v_1 \\ v_2 \\ v_3 \end{array}\right ) aTv1v2v3=v=bTu1u2u3=bTMv1v2v3

这表明

a = M T b b = ( M T ) − 1 a \bm a = M^T\bm b \qquad\qquad \bm b = (M^T)^{-1} \bm a a=MTbb=(MT)1a

小结:如果知道两个坐标系 v v v系和 u u u系,并且从 v v v系到 u u u系之间的旋转变换关系 M M M,即 u = M v u=Mv u=Mv,而同一点在 v v v系下的坐标为 a = ( α 1 , α 2 , α 3 ) T a=(\alpha_1, \alpha_2, \alpha_3)^T a=(α1,α2,α3)T,在 u u u系下的坐标为 ( β 1 , β 2 , β 3 ) T (\beta_1, \beta_2, \beta_3)^T (β1,β2,β3)T,则 b = ( M T ) − 1 a b = (M^T)^{-1} a b=(MT)1a


1.2 广义坐标系

然而,在计算机图形学中,上述三维坐标系的关系不够完善。尽管矩阵 M M M能够用来表示向量旋转和伸缩,但是不能用来处理点(及物体)的平移(translate)运动。

事实上,任意一个仿射变换都可以通过乘以一个 3 × 3 3\times3 3×3的矩阵,再按照一个向量移动实现。然而,在计算机图像学中,我们更倾向于使用广义坐标系(frame)达到相同效果。

广义坐标系是一个更丰富的坐标系,我们将一个参考点 P 0 P_0 P0添加进三个线性独立的基向量 v 1 , v 2 , v 3 v_1, v_2, v_3 v1,v2,v3,向量 v v v和点 P P P分别表示为

v = α 1 v 1 + α 2 v 2 + α 3 v 3 P = P 0 + α 1 v 1 + α 2 v 2 + α 3 v 3 \begin{aligned} &v = &\alpha_1 v_1 + \alpha_2 v_2 + \alpha_3 v_3 \\ &P = P_0 + & \alpha_1 v_1 + \alpha_2 v_2 + \alpha_3 v_3 \end{aligned} v=P=P0+α1v1+α2v2+α3v3α1v1+α2v2+α3v3

我们可以使用向量与矩阵的概念重新表示向量 v v v和点 P P P

v = ( α 1   α 2   α 3   0 ) ( v 1 v 2 v 3 P 0 ) P = ( α 1   α 2   α 3   1 ) ( v 1 v 2 v 3 P 0 ) v = (\alpha_1 \ \alpha_2 \ \alpha_3 \ 0) \left ( \begin{array}{cc}v_1 \\ v_2 \\ v_3 \\ P_0 \end{array} \right ) \qquad P = (\alpha_1 \ \alpha_2 \ \alpha_3 \ 1) \left ( \begin{array}{cc}v_1 \\ v_2 \\ v_3 \\ P_0 \end{array} \right ) v=(α1 α2 α3 0)v1v2v3P0P=(α1 α2 α3 1)v1v2v3P0

系数 α 1 , α 2 , α 3 , 0 \alpha_1,\alpha_2 ,\alpha_3 , 0 α1,α2,α3,0 α 1 , α 2 , α 3 , 1 \alpha_1 , \alpha_2 ,\alpha_3 ,1 α1,α2,α3,1称为 v v v P P P的其次坐标(homogeneous coordinates)。


二、 广义坐标变换


假设我们想把一个坐标系 ( v 1 , v 2 , v 3 , P 0 ) (v_1, v_2, v_3, P_0) (v1,v2,v3,P0) 转换为一个新的坐标系 ( u 1 , u 2 , u 3 , Q 0 ) (u_1, u_2, u_3, Q_0) (u1,u2,u3,Q0)。把新的基向量及参考点使用原始的表示为,

u 1 = a 11 v 1 + a 12 v 2 + a 13 v 3 u 2 = a 21 v 1 + a 22 v 2 + a 23 v 3 u 1 = a 31 v 1 + a 32 v 2 + a 33 v 3 Q 0 = a 41 v 1 + a 42 v 2 + a 43 v 3 + P 0 \begin{aligned} &u_1 = a_{11} v_1 + a_{12} v_2 + a_{13} v_3 \\ &u_2 = a_{21} v_1 + a_{22} v_2 + a_{23} v_3 \\ &u_1 = a_{31} v_1 + a_{32} v_2 + a_{33} v_3 \\ &Q_0 = a_{41} v_1 + a_{42} v_2 + a_{43} v_3 + P_0 \end{aligned} u1=a11v1+a12v2+a13v3u2=a21v1+a22v2+a23v3u1=a31v1+a32v2+a33v3Q0=a41v1+a42v2+a43v3+P0

由此可以得到一个 4 × 4 4\times4 4×4的矩阵

( a 11 a 12 a 12 0 a 21 a 22 a 23 0 a 31 a 32 a 33 0 a 41 a 42 a 43 1 ) \left ( \begin {array}{cc} a_{11} & a_{12} & a_{12} & 0 \\ a_{21} & a_{22} & a_{23} & 0 \\ a_{31} & a_{32} & a_{33} & 0 \\ a_{41} & a_{42} & a_{43} & 1 \end{array} \right ) a11a21a31a41a12a22a32a42a12a23a33a430001

和三维向量坐标类似,我们使用 a a a b b b分别表示两个坐标系下的同一个点或向量,则

a T ( v 1 v 2 v 3 P 0 ) = b T ( u 1 u 2 u 3 Q 0 ) = b T M ( v 1 v 2 v 3 P 0 ) \bm a^T \left ( \begin{array}{c} v_1 \\ v_2 \\ v_3 \\P_0 \end{array}\right ) =\bm b^T \left ( \begin{array}{c} u_1 \\ u_2 \\ u_3 \\ Q_0 \end{array}\right ) =\bm b^T M \left ( \begin{array}{c} v_1 \\ v_2 \\ v_3 \\P_0 \end{array}\right ) aTv1v2v3P0=bTu1u2u3Q0=bTMv1v2v3P0

这表明

a = M T b b = ( M T ) − 1 a \bm a = M^T \bm b \qquad \qquad \bm b = (M^T)^{-1} \bm a a=MTbb=(MT)1a


三、仿射变换

使用转置的矩阵

M T = ( a 11 a 21 a 31 0 a 12 a 22 a 32 0 a 13 a 23 a 33 0 0 0 0 1 ) M^T = \left ( \begin {array}{cc} a_{11} & a_{21} & a_{31} & 0 \\ a_{12} & a_{22} & a_{32} & 0 \\ a_{13} & a_{23} & a_{33} & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) MT=a11a12a130a21a22a230a31a32a3300001

表示任意一个仿射变换,有12个自由度,可以看作一个由九个元素 3 x 3 3x3 3x3的矩阵和三个分量的平移向量组成。

最重要的几种仿射变换是旋转(rotations),伸缩(scalings)和平移(translations)。事实上,其他的仿射变换都可以通过这三者组合表示出来。

仿射变换对于线段同样适用。如果一条线段

P ( α ) = ( 1 − α ) P 0 + α P 1 P(\alpha) = (1-\alpha ) P_0 + \alpha P_1 P(α)=(1α)P0+αP1

使用其次坐标表示为

p ( α ) = ( 1 − a ) p 0 + α p 1 \bm p(\alpha) = (1-a) \bm p_0 + \alpha \bm p_1 p(α)=(1a)p0+αp1

对于另一个坐标系,将线段 P P P乘以一个仿射变换矩阵 M M M即可得到新的表示

M p ( α ) = ( 1 − α ) M p 0 + α M p 1 M \bm p(\alpha) = (1-\alpha) M \bm p_0 + \alpha M \bm p_1 Mp(α)=(1α)Mp0+αMp1

同样地,仿射变换可以将三角形映射为三角形,将四面体映射为四面体。因此OpenGL里的许多物体都可以仅使用它们的顶点实现变换。


四、旋转、平移、伸缩和剪切


4.1 平移

平移(translation)是将一个点沿着特定方向移动一段距离的操作。将点 P P P沿着向量 d d d方向移动得到

P ′ = P + d P' = P + d P=P+d

我们可以把这个等式写为齐次坐标形式

p ′ = p + d \bm {p' = p + d} p=p+d

其中

p = ( x y z 1 ) p ′ = ( x ′ y ′ z ′ 1 ) d = ( α x α y α z 0 ) \bm p = \left ( \begin {array}{c} x \\ y \\ z \\ 1 \end{array} \right ) \qquad \bm p' = \left ( \begin {array}{c} x' \\ y' \\ z' \\ 1 \end{array} \right ) \qquad \bm d = \left ( \begin {array}{c} \alpha_x \\ \alpha_y \\ \alpha_z \\ 0 \end{array} \right ) \qquad p=xyz1p=xyz1d=αxαyαz0

因此

x ′ = x + α x y ′ = y + α y z ′ = z + α z x' = x+ \alpha_x \qquad y' = y+ \alpha_y \qquad z' = z+ \alpha_z x=x+αxy=y+αyz=z+αz

容易得到实现 p ′ = T p \bm p' = T \bm p p=Tp 的变换矩阵 T T T

T = T ( α x , α y , α z ) = ( 1 0 0 α x 0 1 0 α y 0 0 1 α z 0 0 0 1 ) T = T(\alpha_x, \alpha_y, \alpha_z) = \left ( \begin{array}{c} 1 & 0 & 0 & \alpha_x \\ 0 & 1 & 0 & \alpha_y \\ 0 & 0 & 1 & \alpha_z \\ 0 & 0 & 0 & 1 \end{array} \right) T=T(αx,αy,αz)=100001000010αxαyαz1

矩阵 T T T称为平移矩阵(translation matrix)。容易验证平移矩阵的逆为

T − 1 ( α x , α y , α z ) = T ( − α x , − α y , − α z ) T^{-1} (\alpha_x, \alpha_y, \alpha_z) = T(-\alpha_x, -\alpha_y,- \alpha_z) T1(αx,αy,αz)=T(αx,αy,αz)


4.2 旋转

旋转(rotation)取决于旋转轴与绕旋转轴转动的角度。首先考虑在原来坐标系的一个平面内的旋转(注:例如绕z轴),如果点 ( x , y ) (x,y) (x,y)的极坐标为

x = ρ cos ⁡ ϕ y = ρ sin ⁡ ϕ x = \rho \cos \phi \qquad y = \rho \sin \phi x=ρcosϕy=ρsinϕ

旋转的角度记为 θ \theta θ,新的位置记为 ( x ′ , y ′ ) (x', y') (x,y),那么

x ′ = ρ cos ⁡ ( ϕ + θ ) y ′ = ρ sin ⁡ ( ϕ + θ ) x' = \rho \cos(\phi + \theta) \qquad y' = \rho \sin (\phi + \theta) x=ρcos(ϕ+θ)y=ρsin(ϕ+θ)

展开易得

x ′ = x cos ⁡ θ − y sin ⁡ θ y ′ = x sin ⁡ θ + y cos ⁡ θ x' = x\cos \theta - y \sin \theta \\ y' = x \sin \theta + y \cos \theta x=xcosθysinθy=xsinθ+ycosθ

或者

( x ′ y ′ ) = ( cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ) ( x y ) \left ( \begin{array}{c} x' \\ y' \end{array} \right ) = \left ( \begin{array}{c} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{array} \right ) \left ( \begin{array}{c} x \\ y \end{array} \right ) (xy)=(cosθsinθsinθcosθ)(xy)

因此分别绕 z , x , y z,x,y z,x,y旋转得到的旋转矩阵为

R z = R z ( θ ) = ( cos ⁡ θ − sin ⁡ θ 0 0 sin ⁡ θ cos ⁡ θ 0 0 0 0 1 0 0 0 0 1 ) R_z = R_z(\theta) = \left ( \begin{array}{c} \cos \theta & -\sin \theta & 0 & 0\\ \sin \theta & \cos \theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) Rz=Rz(θ)=cosθsinθ00sinθcosθ0000100001

R x = R x ( θ ) = ( 1 0 0 0 0 cos ⁡ θ − sin ⁡ θ 0 0 sin ⁡ θ cos ⁡ θ 0 0 0 0 1 ) R_x = R_x(\theta) = \left ( \begin{array}{c} 1 & 0 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta & 0 \\ 0 & \sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) Rx=Rx(θ)=10000cosθsinθ00sinθcosθ00001

R y = R y ( θ ) = ( cos ⁡ θ 0 sin ⁡ θ 0 0 1 0 1 − sin ⁡ θ 0 cos ⁡ θ 0 0 0 0 1 ) R_y = R_y(\theta) = \left ( \begin{array}{c} \cos \theta & 0 & \sin \theta & 0 \\ 0 & 1 & 0 & 1\\ -\sin \theta & 0 & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) Ry=Ry(θ)=cosθ0sinθ00100sinθ0cosθ00101

注: R y R_y Ry sin ⁡ θ \sin \theta sinθ符号相反,是由于根据右手螺旋定则 x → y → z → x x\to y \to z \to x xyzx的顺序。

上述三个式子中正的旋转角度 θ \theta θ都是符合右手螺旋定则绕 x , y , z x,y,z x,y,z轴进行的旋转。使用 R = R ( θ ) R = R(\theta) R=R(θ)代表上面任意矩阵,则逆为

R − 1 ( θ ) = R ( − θ ) = R T ( θ ) R^{-1} (\theta) = R(-\theta) = R^T (\theta) R1(θ)=R(θ)=RT(θ)

平移和旋转都是刚体运动(solid-body transformations)的例子:这种运动不改变物体的大小和尺寸。


4.3 伸缩

伸缩(scaling) 可以独立应用于三个坐标轴,如果将点 ( x , y , z ) (x,y,z) (x,y,z)转化为新的点

x ′ = β x x y ′ = β y y z ′ = β z z x' = \beta_x x \qquad y' = \beta_y y \qquad z' = \beta_z z x=βxxy=βyyz=βzz

这样得出相应的矩阵为

S = S ( β x , β y , β z ) = ( β x 0 0 0 0 β y 0 0 0 0 β z 0 0 0 0 1 ) S = S(\beta_x, \beta_y, \beta_z) = \left ( \begin{array}{c} \beta_x & 0 & 0 & 0 \\ 0 & \beta_y & 0 & 0 \\ 0 & 0 & \beta_z & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) S=S(βx,βy,βz)=βx0000βy0000βz00001

其逆为

S − 1 ( β x , β y , β z ) = S ( 1 / β x , 1 / β y , 1 / β z ) S^{-1}(\beta_x, \beta_y, \beta_z) = S(1/\beta_x, 1/\beta_y, 1/\beta_z) S1(βx,βy,βz)=S(1/βx,1/βy,1/βz)

如果伸缩因子 β x , β y , β z \beta_x, \beta_y, \beta_z βx,βy,βz相等,那么伸缩变化是等尺度的(uniform):物体保持形状不变但是改变尺寸。否则称伸缩变换时非等尺度的(non-uniform),物体发生变形。


4.4 剪切

剪切(shears)可以看作平移、旋转和伸缩的组合,但是有一些独特的性质。

对于任意标量 a a a,一个朝 x x x 方向的剪切定义为

x ′ = x + ( cot ⁡ θ ) y y ′ = y z ′ = z x' = x + (\cot \theta) y \qquad y' = y \qquad z' = z x=x+(cotθ)yy=yz=z

相应的剪切矩阵为

H x ( θ ) = ( 1 cot ⁡ θ 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ) H_x (\theta) = \left ( \begin{array}{cc} 1 & \cot \theta & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right ) Hx(θ)=1000cotθ10000100001

其逆为

H x − 1 ( θ ) = H x ( − θ ) H_x^{-1} (\theta) = H_x(-\theta) Hx1(θ)=Hx(θ)


五、绕任意轴旋转

我们怎样找到一个描述任意一点 p 0 p_0 p0 绕一个方向 u = p 2 − p 1 u = p_2 - p_1 u=p2p1 旋转角度 θ \theta θ 的矩阵呢?

答案是将次矩阵分解为我们已知的一系列矩阵之和。同样假设 u u u 的模为 1,第一步,使用平移简化原问题的旋转问题:

M = T ( p 0 ) R T ( − p 0 ) M = T(p_0) R T(-p_0) M=T(p0)RT(p0)

为了确定旋转矩阵 R R R,首先通过转动 θ x \theta_x θx θ y \theta_y θy 两个角度使得 u u u z z z 轴重合;然后绕 z z z 轴旋转指定的角度 θ \theta θ;最后再旋转相同的角度,因此

R = R x ( − θ x ) R y ( − θ y ) R z ( θ ) R y ( θ y ) R x ( θ x ) R = R_x (-\theta_x) R_y (-\theta_y) R_z (\theta) R_y(\theta_y) R_x (\theta_x) R=Rx(θx)Ry(θy)Rz(θ)Ry(θy)Rx(θx)

这里还有绕 u = ( α x , α y , α z ) u=(\alpha_x, \alpha_y, \alpha_z) u=(αx,αy,αz) 旋转的角度 θ x \theta_x θx θ y \theta_y θy 是未知的。第一次旋转 R x ( θ x ) R_x (\theta_x) Rx(θx) 将向量 u u u x x x 轴旋转直至它位于 y = 0 y=0 y=0 的平面。使用简单的几何学只是,可以得到

cos ⁡ θ x = α z / d sin ⁡ θ x = α y / d \cos \theta_x = \alpha_z / d \qquad \sin \theta_x = \alpha_y /d cosθx=αz/dsinθx=αy/d

其中, d = ( α y 2 + α z 2 ) d = \sqrt(\alpha_y^2 + \alpha_z^2) d=( αy2+αz2),因此,不需要明确地得到 θ x \theta_x θx,可以得到

R x = R x ( θ ) = ( 1 0 0 0 0 α z / d − α y / d 0 0 α y / d α z / d 0 0 0 0 1 ) R_x = R_x(\theta) = \left ( \begin{array}{c} 1 & 0 & 0 & 0 \\ 0 & \alpha_z / d & -\alpha_y /d & 0 \\ 0 & \alpha_y /d & \alpha_z / d & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) Rx=Rx(θ)=10000αz/dαy/d00αy/dαz/d00001

在第二次重合中,可以得到

cos ⁡ θ y = d sin ⁡ θ y = − α x \cos \theta_y = d \qquad \sin \theta_y = - \alpha_x cosθy=dsinθy=αx

易得

R x = R x ( θ ) = ( d 0 − α x 0 0 1 0 0 α x 0 d 0 0 0 0 1 ) R_x = R_x(\theta) = \left ( \begin{array}{c} d & 0 & -\alpha_x & 0 \\ 0 & 1 & 0 & 0 \\ \alpha_x & 0 & d & 0 \\ 0 & 0 & 0 & 1 \end{array} \right ) Rx=Rx(θ)=d0αx00100αx0d00001

注:原文 α x \alpha_x αx 符号相反,疑似有误。


六、关于四元数的一些知识


6.1 基本运算

四元数提供了一种新的描述旋转的方式,而且已经用于硬件实现。

在复数域,旋转一个角度 ϕ \phi ϕ 可以表示为乘以一个复数

e i ϕ = cos ⁡ ϕ + i sin ⁡ ϕ e^{i \phi} = \cos \phi + i \sin \phi eiϕ=cosϕ+isinϕ

这样可以将一个给定的点 r e i θ r e^{i\theta} reiθ 旋转得到新的点

r e i θ e i ϕ = r e i ( θ + ϕ ) re^{i\theta} e^{i \phi} = r e^{i(\theta + \phi)} reiθeiϕ=rei(θ+ϕ)

类似地,四元数可以优雅地描述三维空间中的旋转。一个四元数有一个标量和一个向量组成,

a = ( q 0 , q 1 , q 2 , q 3 ) = ( q 0 , q ) a = (q_0, q_1, q_2, q_3) = (q_0, \bm q) a=(q0,q1,q2,q3)=(q0,q)

可以把向量部分 q q q 写为

q = q 1 i + q 2 j + q 3 k q = q_1 \bm i + q_2 \bm j + q_3 \bm k q=q1i+q2j+q3k

其中, i , j , k \bm i , \bm j, \bm k i,j,k 类似三维空间内的单位向量,并且满足

i 2 = j 2 = k 2 = − 1 \bm i^2 = \bm j^2 = \bm k^2 = -1 i2=j2=k2=1

i j = k = − j i j k = i = − k j k i = j = − i k \bm i \bm j = \bm k = - \bm j \bm i \qquad \bm j \bm k = \bm i = - \bm k \bm j \qquad \bm k \bm i = \bm j = - \bm i \bm k ij=k=jijk=i=kjki=j=ik

根据以上性质容易计算两个四元数的和与积,设 a = ( q 0 , q ) , b = ( p 0 p ) a = (q_0, \bm q), b=(p_0 \bm p) a=(q0,q),b=(p0p),则

a + b = ( q 0 + p 0 , q + p ) a + b = (q_0 + p_0 , \bm q + \bm p) a+b=(q0+p0,q+p)

a b = ( q 0 p 0 − q ⋅ p , q 0 p + p 0 q + q × p ) ab = (q_0 p_0 - \bm q \cdot \bm p, q_0 \bm p + p_0 \bm q + \bm q \times \bm p) ab=(q0p0qp,q0p+p0q+q×p)

a a a 的幅度和逆分别为

∣ a ∣ = q 0 2 + q ⋅ q | a | = \sqrt{q_0^2 + \bm q \cdot \bm q} a=q02+qq

a − 1 = 1 ∣ a ∣ ( q 0 , − q ) a^{-1} = \frac{1}{|a|} (q_0 , -\bm q) a1=a1(q0,q)


6.2 旋转

假设 v ∈ R 3 \bm v \in R^3 vR3 是单位向量,令 p \bm p p 是一个任意点, p ′ \bm p' p是点 p \bm p p v \bm v v 轴旋转后的点。为了寻找点 p ′ \bm p' p 对应的四元数,零 r r r

r = ( cos ⁡ θ 2 , sin ⁡ θ 2 ⋅ v ) r = (\cos \frac{\theta}{2}, \sin \frac{\theta}{2} \cdot \bm v) r=(cos2θ,sin2θv)

一个单位长度的四元数,其逆为

r − 1 = ( cos ⁡ θ 2 , − sin ⁡ θ 2 ⋅ v ) r^{-1} = (\cos \frac{\theta}{2}, -\sin \frac{\theta}{2} \cdot \bm v) r1=(cos2θ,sin2θv)

那么如果 p p p p ′ p' p 是四元数

p = ( 0 , p ) p ′ = ( 0 , p ′ ) p = (0, \bm p) \qquad p' = (0, \bm p') p=(0,p)p=(0,p)

可以证明

p ′ = r − 1 p r p' = r^{-1} p r p=r1pr

接下来验证上式的正确!根据乘法运算法则,可以计算得 p ′ p' p 确实有 ( 0 , p ′ ) (0, \bm p') (0,p) 的形式,并且

p ′ = cos ⁡ 2 θ 2 p + sin ⁡ 2 θ 2 ( v ⋅ p ) v + 2 sin ⁡ θ 2 cos ⁡ θ 2 ( v × p ) + sin ⁡ 2 θ 2 v × ( v × p ) \bm p' = \cos ^2 \frac{\theta}{2} \bm p + \sin^2 \frac{\theta}{2} (\bm v \cdot \bm p) \bm v + 2 \sin \frac{\theta}{2} \cos \frac{\theta}{2} (\bm v \times \bm p) + \sin ^2 \frac{\theta}{2} \bm v \times (\bm v \times \bm p) p=cos22θp+sin22θ(vp)v+2sin2θcos2θ(v×p)+sin22θv×(v×p)

利用等式

p = ( v ⋅ p ) v − v × ( v × p ) \bm p = (\bm v \cdot \bm p ) \bm v - \bm v \times (\bm v \times \bm p) p=(vp)vv×(v×p)

并根据三角函数多倍角公式,可得化简结果

p ′ = ( v ⋅ p ) v + cos ⁡ θ ( v × p ) × v + sin ⁡ θ ( v × p ) \bm p' = (\bm v \cdot \bm p ) \bm v + \cos \theta (\bm v \times \bm p) \times \bm v + \sin \theta (\bm v \times \bm p) p=(vp)v+cosθ(v×p)×v+sinθ(v×p)

这个公式很容易从几何意义中得到验证,它是对三个正交向量的线性组合。第一项 ( v ⋅ p ) v (\bm v \cdot \bm p ) \bm v (vp)v p \bm p p 在旋转轴上的投影,第二项和第三项描述了垂直于 v \bm v v 的平面上的旋转。

注意到这个公式清晰地表示了一种正交投影,所有的分量都是对 p \bm p p 的线性变换。这个公式也可以用于在矩阵变换中直接获取相应的系数。

以下是用OpenGL实现键盘控制三角形平移旋转缩放的简单程序。你可以将此代码放入一个C++文件中并编译运行。 ```c++ #include <GL/glut.h> #include <iostream> using namespace std; // 三角形的顶点坐标 GLfloat vertices[][3] = { { -1.0,-1.0,-1.0 },{ 1.0,-1.0,-1.0 }, { 1.0,1.0,-1.0 },{ -1.0,1.0,-1.0 },{ -1.0,-1.0,1.0 }, { 1.0,-1.0,1.0 },{ 1.0,1.0,1.0 },{ -1.0,1.0,1.0 } }; // 三角形的边界顶点索引 GLfloat edges[][2] = { { 0,1 },{ 1,2 },{ 2,3 },{ 3,0 }, { 4,5 },{ 5,6 },{ 6,7 },{ 7,4 },{ 0,4 },{ 1,5 },{ 2,6 },{ 3,7 } }; // 三角形的颜色 GLfloat colors[][3] = { { 1.0,0.0,0.0 },{ 0.0,1.0,0.0 }, { 0.0,0.0,1.0 },{ 1.0,1.0,0.0 },{ 1.0,0.0,1.0 },{ 0.0,1.0,1.0 } }; // 三角形的缩放比例 GLfloat scale = 1.0; // 三角形的平移量 GLfloat transX = 0.0, transY = 0.0, transZ = -5.0; // 三角形的旋转角度 GLfloat rotX = 0.0, rotY = 0.0, rotZ = 0.0; // 执行绘制操作 void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // 平移 glTranslatef(transX, transY, transZ); // 旋转 glRotatef(rotX, 1.0, 0.0, 0.0); glRotatef(rotY, 0.0, 1.0, 0.0); glRotatef(rotZ, 0.0, 0.0, 1.0); // 缩放 glScalef(scale, scale, scale); // 绘制三角形 for (int i = 0; i < 12; i++) { glBegin(GL_LINES); glColor3fv(colors[i / 2]); glVertex3fv(vertices[edges[i][0]]); glVertex3fv(vertices[edges[i][1]]); glEnd(); } glFlush(); glutSwapBuffers(); } // 执行键盘操作 void keyboard(unsigned char key, int x, int y) { switch (key) { // 放大 case 'w': scale += 0.1; break; // 缩小 case 's': scale -= 0.1; break; // 上移 case 'i': transY += 0.1; break; // 下移 case 'k': transY -= 0.1; break; // 左移 case 'j': transX -= 0.1; break; // 右移 case 'l': transX += 0.1; break; // 绕X轴顺时针旋转 case 'x': rotX += 10.0; break; // 绕X轴逆时针旋转 case 'X': rotX -= 10.0; break; // 绕Y轴顺时针旋转 case 'y': rotY += 10.0; break; // 绕Y轴逆时针旋转 case 'Y': rotY -= 10.0; break; // 绕Z轴顺时针旋转 case 'z': rotZ += 10.0; break; // 绕Z轴逆时针旋转 case 'Z': rotZ -= 10.0; break; // 默认 default: break; } glutPostRedisplay(); } // 初始化OpenGL void init() { glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Triangle Transformation"); init(); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } ``` 该程序使用OpenGL绘制了一个三角形,并且可以通过键盘控制其平移旋转缩放。你可以通过按下“w”键和“s”键来放大和缩小三角形,按下“i”、“k”、“j”和“l”键来控制三角形在水平和垂直方向上的平移,按下“x”、“X”、“y”、“Y”、“z”和“Z”键来控制三角形的旋转
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值