四元数原理学习笔记

文章目录

      • 四元数的数学性质
        • 定义
      • Unity中的四元数和旋转

四元数的数学性质

定义

1.1:一般形式
q = s + x i + y j + z k s , x , y , z ∈ R \textbf{q} = s + x\textbf{i} + y\textbf{j} +z\textbf{k}\quad s,x,y,z\in\mathbb R q=s+xi+yj+zks,x,y,zR

1.2:虚数单位的运算规则
四元数将复数中的虚数单位扩充为三个,这三个虚数单位的运算规则是:
i 2 = j 2 = k 2 = ijk = − 1 ij = k , jk = i , ki = j \textbf{i}^2=\textbf{j}^2=\textbf{k}^2=\textbf{ijk}=-1\\ \textbf{ij}=\textbf{k},\textbf{jk}=\textbf{i},\textbf{ki}=\textbf{j} i2=j2=k2=ijk=1ij=k,jk=i,ki=j

四元数的这三个虚数单位以及他们的乘法运算很像是三维空间中三个正交单位向量的叉乘的关系:两个正交的单位向量的叉乘等于另一个单位向量,这个单位向量一定与其他两个单位向量都正交。那不妨就将这三个虚数代表三维空间中的三个正交的单位向量。

1.3:四元数的加法和乘法
四元数的加法和乘法可以看作是复数加法和乘法在虚数单位扩充之后的运算。其加法同样满足交换律,乘法满足结合律。

1.4:四元数的乘积一般式
记向量:
a = x a i + y a j + z a k b = x b i + y b j + z b k \textbf{a}=x_a\textbf{i}+y_a\textbf{j}+z_a\textbf{k}\\ \textbf{b}=x_b\textbf{i}+y_b\textbf{j}+z_b\textbf{k} a=xai+yaj+zakb=xbi+ybj+zbk

依照向量的运算法则,点积和叉乘结果如下:
a ⋅ b = x a x b + y a y b + z a z b a × b = ( y a z b − y b z a ) i + ( z a x b − z b x a ) j + ( x a y b − x b y a ) k \textbf{a}\cdot \textbf{b} = x_ax_b+y_ay_b+z_az_b\\ \textbf{a}\times\textbf{b}=(y_az_b-y_bz_a)\textbf{i}+(z_ax_b-z_bx_a)\textbf{j}+(x_ay_b-x_by_a)\textbf{k} ab=xaxb+yayb+zazba×b=(yazbybza)i+(zaxbzbxa)j+(xaybxbya)k

则两个四元数的乘积可以表示为:
q a q b = [ s a , a ] ⋅ [ s b , b ] = [ s a s b − a ⋅ b , s a b + s b a + a × b ] \begin{aligned} \textbf{q}_a\textbf{q}_b & = [s_a,\textbf{a}]\cdot[s_b,\textbf{b}]\\ &= [s_as_b-\textbf{a}\cdot\textbf{b},s_a\textbf{b}+s_b\textbf{a}+\textbf{a}\times\textbf{b}] \end{aligned} qaqb=[sa,a][sb,b]=[sasbab,sab+sba+a×b]

1.5:纯四元数
纯四元数是实部为 0 0 0的四元数
q = [ 0 , v ] \textbf{q}=[0,\textbf{v}] q=[0,v]

两个纯四元数的乘积为
q a q b = [ 0 , a ] ⋅ [ 0 , b ] = [ − a ⋅ b , a × b ] \begin{aligned} \textbf{q}_a\textbf{q}_b&=[0,\textbf{a}]\cdot[0,\textbf{b}]\\ &=[-\textbf{a}\cdot\textbf{b},\textbf{a}\times\textbf{b}] \end{aligned} qaqb=[0,a][0,b]=[ab,a×b]

1.6:单位四元数
对于向量 v v v,其可以写作其长度(范式)乘以一个单位向量
v = ∣ v ∣ v ^ \textbf{v} = |\textbf{v}|\hat{\textbf{v}} v=vv^
其中
∣ v ^ ∣ = 1 |\hat{\textbf{v}}|=1 v^=1
那么一个单位四元数的定义为实部为 0 0 0,虚部的范式为 1 1 1的四元数
q ^ = [ 0 , v ^ ] \hat{\textbf{q}}=[0,\hat{\textbf{v}}] q^=[0,v^]

将单位四元数与复数中的虚数单位作类比,有如下相似表示:
复 数 : z = a + b i 四 元 数 : q = s + v q ^ \begin{aligned} 复数&:&\textbf{z}=a+b\textbf{i}\\ 四元数&:&\textbf{q}=s+v\hat{\textbf{q}} \end{aligned} z=a+biq=s+vq^

1.7:共轭四元数
一个四元数 q \textbf{q} q的共轭即将其虚部向量取反
q = [ s , v ] q ∗ = [ s , − v ] \textbf{q}=[s,\textbf{v}]\\ \textbf{q}^*=[s,-\textbf{v}] q=[s,v]q=[s,v]
再根据1.4节得到的乘积一般式有:
qq ∗ = [ s 2 + v 2 , 0 ] = s 2 + v 2 \textbf{qq}^*=[s^2+\textbf{v}^2,\textbf{0}]=s^2+v^2 qq=[s2+v2,0]=s2+v2
注意这里的 v 2 \textbf{v}^2 v2是指两个向量的点积,等价于 ∣ v ∣ 2 = v 2 = a 2 + b 2 + c 2 |\textbf{v}|^2=v^2=a^2+b^2+c^2 v2=v2=a2+b2+c2,不可将其看作是 ( a i + b j + c k ) 2 (a\textbf{i}+b\textbf{j}+c\textbf{k})^2 (ai+bj+ck)2再用乘法结合律求解。

1.8:四元数的范数
四元数的范数的平方等于实部的平方加上虚部向量的范数,即
∣ q ∣ 2 = s 2 + v 2 = s 2 + v 2 |\textbf{q}|^2=s^2+\textbf{v}^2=s^2+v^2 q2=s2+v2=s2+v2

qq ∗ = ∣ q ∣ 2 \textbf{qq}^*=|\textbf{q}|^2 qq=q2

1.9:四元数的规范化
四元数的规范化定义为将四元数除以它的范数
q ′ = q |q| \textbf{q}'=\frac{\textbf{q}}{\textbf{|\textbf{q}|}} q=|q|q

1.10:四元数的逆
四元数的逆定义为:存在这样一个四元数 q − 1 \textbf{q}^{-1} q1使得以下式子成立:
qq − 1 = [ 1 , 0 ] = 1 \textbf{qq}^{-1}=[1,\textbf{0}]=1 qq1=[1,0]=1
则称这个四元数 q − 1 \textbf{q}^{-1} q1 q \textbf{q} q的逆。可以证明,四元数的逆可以用下列式子计算得到:
q − 1 = q ∗ ∣ q ∣ 2 \textbf{q}^{-1}=\frac{\textbf{q}^*}{|\textbf{q}|^2} q1=q2q

1.11:四元数的点积
四元数的点积等于实部和虚部各个部分分别相乘,其与向量的点积定义相似:
q 1 = [ s 1 , x 1 i + y 1 j + z 1 k ] q 2 = [ s 2 , x 2 i + y 2 j + z 2 k ] \textbf{q}_1=[s_1,x_1\textbf{i}+y_1\textbf{j}+z_1\textbf{k}]\\ \textbf{q}_2=[s_2,x_2\textbf{i}+y_2\textbf{j}+z_2\textbf{k}] q1=[s1,x1i+y1j+z1k]q2=[s2,x2i+y2j+z2k]
则点积结果为
q 1 q 2 = s 1 s 2 + x 1 x 2 + y 1 y 2 + z 1 z 2 \textbf{q}_1\textbf{q}_2=s_1s_2+x_1x_2+y_1y_2+z_1z_2 q1q2=s1s2+x1x2+y1y2+z1z2
利用四元数的点积,仿照向量的点积,我们可以定义两个四元数之间的夹角 θ \theta θ满足:
c o s θ = q 1 q 2 ∣ q 1 ∣ ∣ q 2 ∣ = s 1 s 2 + x 1 x 2 + y 1 y 2 + z 1 z 2 s 1 2 + x 1 2 + y 1 2 + z 1 2 s 2 2 + x 2 2 + y 2 2 + z 2 2 \begin{aligned} cos\theta&=\frac{\textbf{q}_1\textbf{q}_2}{|\textbf{q}_1||\textbf{q}_2|}\\ &=\frac{s_1s_2+x_1x_2+y_1y_2+z_1z_2}{\sqrt{s_1^2+x_1^2+y_1^2+z_1^2}\sqrt{s_2^2+x_2^2+y_2^2+z_2^2}} \end{aligned} cosθ=q1q2q1q2=s12+x12+y12+z12 s22+x22+y22+z22 s1s2+x1x2+y1y2+z1z2
对于单位四元数来说
c o s θ = s 1 s 2 + x 1 x 2 + y 1 y 2 + z 1 z 2 cos\theta=s_1s_2+x_1x_2+y_1y_2+z_1z_2 cosθ=s1s2+x1x2+y1y2+z1z2

1.12:四元数的旋转
注意,用虚部三个虚数单位分别代表三维空间当中的三个正交单位向量是可行的。但是四元数还有一个实部维度,为了忽略这个维度,我们在描述一个物体的位置的时候,这个实部必须为零。从而描述一个物体的四元数如下:
p = [ 0 , p ] \textbf{p}=[0,\textbf{p}] p=[0,p]
其中 p \textbf{p} p是一个纯四元数(即实部为零的四元数)。

之后,仿照复数在二维平面的几何含义,我们假设一个四元数 q = [ c o s θ , s i n θ v ^ ] \textbf{q}=[cos\theta,sin\theta \hat{\textbf{v}}] q=[cosθ,sinθv^]表示将作用的物体绕着轴 v ^ \hat{\textbf{v}} v^旋转 θ \theta θ。具体的演算过程这里略过。
四元数的发明者Hamilton发现当 v ^ \hat{\textbf{v}} v^ p \textbf{p} p正交时, p ′ = qp \textbf{p}'=\textbf{q}\textbf{p} p=qp是可行的。但是当不正交的时候,得出的 p ′ \textbf{p}' p不是一个纯四元数,那就不能表示成三维空间的一个坐标。为了解决这个问题,Hamilton将上述式子再右乘一个 q \textbf{q} q的逆,即
p ′ = pq p − 1 \textbf{p}'=\textbf{p}\textbf{q}\textbf{p}^{-1} p=pqp1
得出来的就是一个纯四元数,而且原四元数的范数保持不变。即有: ∣ p ′ ∣ = ∣ p ∣ |\textbf{p}'|=|\textbf{p}| p=p。但是,Hamilton发现,这样旋转的角度总是比预期高一倍,即实际旋转了 2 θ 2\theta 2θ。于是,实际运算中我们应该写:
q = [ c o s 1 2 θ , s i n 1 2 θ v ^ ] \textbf{q}=[cos\frac{1}{2}\theta,sin\frac{1}{2}\theta \hat{\textbf{v}}] q=[cos21θ,sin21θv^]
这就是旋转四元数的一般形式。

Unity中的四元数和旋转

在Unity中,并不需要用四元数去表达一个物体在某个坐标系下的坐标,所以上述的 q \textbf{q} q是不存在的。每个物体的旋转状态都只用一个 p \textbf{p} p就足以描述。它被存放在transform.rotation或者transform.localrotation中。
例如,假设 p = c o s 1 5 ∘ + s i n 1 5 ∘ j \textbf{p} = cos15^\circ+sin15^\circ\textbf{j} p=cos15+sin15j,则在transform.rotation中表示物体从初始状态已经绕了局部坐标系的y轴旋转了 3 0 ∘ 30^\circ 30
当你需要对一个物体进行旋转的时候,给一个角度angle和一个代表旋转轴的向量axis,用Quaternion.AngleAxis(angle, axis)求出对应的旋转四元数之后,左乘以被旋转物体的rotation即可。即

Quaternion q = Quaternion.AngleAxis(angle, axis);
transform.rotation = q * transform.rotation;

当然,假设你自己开发一款引擎,用纯四元数表示一个物体的坐标,此时,假设可能有设置物体的位置的代码如下:

// 注意在Unity中,实部被放在了最后一位
// set the position to (1,1,1), note that the real part must be zero.
transform.position = new Quaternion(1,1,1,0);

那么,当你绕着某个不经过物体中心的轴旋转的时候,物体的位置也会发生变化。此时,要想得到物体的正确位置,应该做如下变换

// Rotate the object, the q is the rotation quaternion
transform.rotation = q * transform.rotation;
transform.position = q * transform.position * Quaternion.Inverse(q);

其中,Quaternion.Inverse()代表求解一个四元数的逆。

在Unity中,Inspector面板上的Rotation设置是不足以描述一个物体的旋转的状态的。因为它固定了旋转轴分别为局部坐标系下的三根轴。设置Rotation属性是不会导致Position的变化的。但是,在代码中设置物体的transform.rotation却可能导致物体位置的变化,因为旋转轴可能不通过物体中心点(即pivot点)。
最后,Unity中的四元数是规范化的。因为Unity不使用四元数来描述物体位置,就不需要关注四元数的范式,Unity仅仅只需要知道描述旋转时的旋转轴的方向和旋转角度即可,而方向和角度是范数无关的。当物体无旋转时,虚部为0,实部为1,四元数的范数永远等于1。

你可能感兴趣的:(Unity游戏开发)