游戏物理数学之《四元数Quaternion》

本篇博本对于四元数的探究,参考了多篇相关论文、博文和书籍,对有关于四元数的知识进行了汇总与提炼,并以通俗易懂的语言且尽可能详尽地去解释相关知识点。涉及四元数的起源与概念解释,数学特性与相关公式推导,以及其在游戏中的运用及例子。

其中主要参考资料如下:
《三维转动的四元数表述》刘俊峰 (复旦大学 光科学与工程系 ,上海  200433)
《Mathematics for 3D Game Programming&Computer Graphics》Eric Lengyel
《知乎回答》Yang Eninala (杜克大学 生物化学博士)
《四元数(Quaternion)和旋转》乐乐 (上海交通大学 数字媒体系 )
《Essential Mathematics for Games and Interactive Applications》(Third Edition)
《Understanding Quaternions》Jim Van Verth Software Engineer, Google

学无止境,如苦海行舟,所谓独苦苦而不如众苦苦╮(╯▽╰)╭,有共同追求的朋友也许我们可以加个好友,相互学习印证,一同进步。(见我博客上方联系信息,或博文下留言,( ̄。 ̄)闲人勿扰,感谢)


一、四元数数学

(一)介绍

(1)什么是四元数?

  首先我们来回忆一下,在我们高中时学的复数,其由实部和虚部组成,即 x=a + bi,a是实部,i是虚数单位,且i² = -1;
  而四元数,它本质上是一种高阶复数,一种形如 A = a + bi + cj + dk 的数。数学家把四元数集合称为Hamilton四元数环,表示为H,可以看作一个四维向量空间,其包含了3个虚数单位和1个实部,满足i² = j² = k² = -1;

(2)四元数的起源与说明

  There’s a story that Hamilton wrote in his memoirs, about him coming down tobreakfast and his son asking him, “Papa, can you multiply triplets?” and he would sadly respond, “No, I can only add and subtract them.” The problem is those ij and ji terms (and as it turns out, the order matters). Also want multiplication that avoids
zero divisors, i.e. we don’t want non-zero numbers that multiply together to produce zero (every non-zero number needs an inverse – this is known as a division algebra).Nothing he came up with three terms would work. (Cross product doesn’t work –cross product of parallel vectors is zero.)
  四元数由Hamilton发明,这一发明起源于十九世纪的某一天。Hamilton在他的回忆里就写着这么一个故事,有一个早上,Hamilton下楼吃早饭。这时他的儿子问他:“爸爸,我们能够对三元数组(triplet,可以理解为三维向量)做乘法运算么?”Hamilton说“不行,我只能加减它们。”问题是那些 ij 和 ji 的关系(事实证明,顺序很重要)。也希望是一个能避免零因子的乘法,即我们不希望非零数字乘在一起产生零(每个非零数字都需要一个逆——这被称为可除代数)。Hamilton提出的三个条件都行不通。(叉乘行不通——平行向量的叉乘为零)。
  十九世纪的Hamilton也许确实不知道内积(点乘)和外积(叉乘),但是他知道,他想要的三维向量乘法要比内积和外积运算“高大上”很多。
  这一乘法运算要满足下列四条性质:
   1. 运算产生的结果也要是三维向量;
   2.存在一个元运算,任何三维向量进行元运算的结果就是其本身;
   3.对于任何一个运算,都存在一个逆运算,这两个运算的积是元运算; 
   4.运算满足结合律;
   
  换而言之,Hamilton想定义的不是一个简单的映射关系,而是一个群!(后来我们知道四元数所在群为S3,而四元数所代表的三维旋转是SO(3),前者是后者的两倍覆盖)内积连性质1都不满足,外积不满足性质3。
  In 1843, as Hamilton was walking along the Royal Canal under the Brougham Bridge in Dublin, he had his insight – with 3 imaginary values he could get a complete system of numbers where multiplication provided proper inverses. He was so excited he carved the first set of equations onto the bridge. Notice that now multiplication is no longer commutative - the imaginary values are anticommutative. If you’re familiar with cross products this may seem very familiar – in fact the cross product comes from quaternion math.
  Hamilton就这么被自己儿子提出的问题难倒了。经历了无数个日日夜夜,他绞尽脑汁也没想明白这个问题。终于有一天(1843年的一天),Hamilton在都柏林皇家运河上的Brougham桥上走着走着,突然意识到了,通过3个虚数可以获得一个完整的数字系统,其乘法提供了适合的逆;自己所需要的运算在三维空间中是不可能实现的,但在四维空间中是可以的。他是如此的兴奋,以至于把四元数的公式刻在桥上。注意:现在的这个乘法不再是可交替的(即不满足交换律),虚数是不可交替的;如果您熟悉叉乘的话,这看起来将似曾相识——事实上叉乘是来自四元数数学。(实在不知道怎么翻译更好了,原文来自《Essential Mathematics for Games and Interactive Applications》,可自行查阅)
  其实,四元数有四个变量,完全可以被看作一个四维向量。单位四元数(norm=1)则存在于四维空间的一个球面上。
  q₁q₂,四元数q₁乘以四元数q₂其实可以看作:
  (1)对q₁进行q₂左旋转;
  (2)或对q₂进行q₁右旋转;
  所以从始至终,四元数定义的都是四维旋转,而不是三维旋转。任意的四维旋转都可以唯一的拆分为一个左旋转和一个右旋转,表达出来就是qᴸPqᴿ。这里,我们对四元数(四维向量)P进行了一个左旋转qᴸ和一个右旋转qᴿ。结果当然是一个四元数,符合性质1。这个运算也同时符合性质2,3,4。
  同时,Hamilton也给出了四元数的加法 、乘法规则以及四元数的逆和模 ,指出四元数能通过旋转 、伸长或缩短将一个给定的矢量变成另一个矢量。

(二)四元数相关公式及其推导

(1)四元数q的定义

  In mathematics , the quaternions are a number system that extends the complex numbers.
  数学中,四元数是扩展复数的数字系统。一般表现形式如下:
  q= < w,x,y,z > = w + xi + yj + zk ;(w、x、y、z是实数,i、j、k是虚数;)
  或者:q= S + V;(S=w, V=(xi , yj , zk))

(2)虚数基元i、j、k的运算规则 (i、j、k可理解为xyz轴的单位矢量)

  i² = j² = k² = -1; (虚数的平方为-1,其0次方为1)
  i* = -i; j* = -j; k* = -k;(虚数的逆为其负值,即共轭)
  ij = k; jk = i; ki = j;(根据ijkijki…的顺序,任意连续两位相乘为后一位)
  ij = -ji; jk = -kj; ki = -ik;(两虚数乘法不符合交换律)

(3)四元数乘法(先不管其有什么意义)

  1. 两个四元数的乘法按多项式乘法进行,可以把这种乘法叫做直乘;
   q₁q₂=(w₁+x₁i+y₁j+z₁k)(w₂+x₂i+y₂j+z₂k)
      =  (w₁w₂-x₁x₂-y₁y₂-z₁z₂)
       + (w₁x₂+x₁w₂+y₁z₂-z₁y₂)i
       + (w₁y₂+y₁w₂+z₁x₂-x₁z₂)j
       + (w₁z₂+z₁w₂+x₁y₂-y₁x₂)k
  这是推导过程:(很简单)
这里写图片描述

  2. 令向量V= xi + yj + zk (上文说过,i、j、k可以理解为xyz轴的单位向量)
   即:
   V₁V₂=(x₁ i+y₁j+z₁k)(x₂i+y₂j+z₂k)
      =-(x₁x₂+y₁y₂+z₁z₂)
       + (y₁z₂-z₁z₂)i
       + (z₁x₂-x₁z₂)j
       + (x₁y₂-y₁x₂)k
      = -V₁·V₂ + V₁×V₂  (这个结论很重要!!!)
   这是推导过程:(仅对外积部分进行说明)
这里写图片描述

补充:(其实这个都是没必要论证的,都是规定)
论证    ① i² = j² = k² = -1;
      ② ij = k; jk = i; ki = j;
      ③ ij = -ji; jk = -kj; ki = -ik;

证明① :ii=-i·i + i×i,因为i和i为平行的单位向量,cos90°=1且|i|=1,-i·i = -|i||i| cos90°=-1(关于点乘,可以自行百度);因为sin90°=0,|i×i| = |i||i| sin90° = 0,为0向量,即结果为0;所以ii = -1;

证明②:ij = -i·j + i×j,因为 i 和 j 垂直,cos90°=0,即 ij = i×j,i×j(叉乘)的结果为垂直于i j共面的一个向量,参考上图的a × b。假设 i 对应x轴(同a),j 对应y轴(同b),k 对应z轴(同a × b),有 i×j=k,既 ij = k;

证明③:ij = i×j,-ji = -j×i,参考上图,j 对应 b,i 对应 ab × a = -a × b,即 i×j = -j×i,即 ij = -ji;(关于叉乘,可以自行百度)

   3.两个四元数相乘的另一种表达方式
    q₁q₂=(S₁+V₁)(S₂+V₂
       =S₁S₂ + S₁ V₂ + S₂ V₁ + V₁V₂
       =S₁S₂ + S₁ V₂ + S₂ V₁ - V₁·V₂ + V₁×V₂

通过此方法,将向量的点乘和叉乘纳入了四元素的乘法之中;
该乘法满足交换律:q₁q₂q₃ = (q₁q₂)q₃ = q₁(q₂q₃)
该乘法满足分配律:λ(q₁ + q₂)=λq₁ + λq₂

   4.四元数的共轭运算(*表示取共轭运算)
    ① q*=(S,-V)=(w,-xi , -yj , -zk)
    ②(q₁q₂* = q₂*q₁*
    这是②的推导过程:
这里写图片描述

可以使用共轭提取四元数的标量和矢量部分。 q的标量部分是( q + q* )/ 2 , q的矢量部分是( q - q* )/ 2 。

   5.四元数q=w + xi + yj + zk的范数和模

   ||q|| = w²+ x² + y² + z²
   |q| = √(w² + x^² + y² + z²)
   即 |q|² = ||q||

   6.将矢量点乘V₁·V₂和矢量叉V₁×V₂表示为直乘的组合V₁V₂

   V₁·V₂ = -1/2(V₁V₂ + V₂V₁
   V₁×V₂ = 1/2(V₁V₂ - V₂V₁

   以下是推导过程:
这里写图片描述
   这里写图片描述

   7.Vˉ¹V=1定义非零矢量的逆
    V*V = -(-VV = V·V = ||V||
    Vˉ¹ = V*/||V||  (这个结论要旋转会用到!)
   以下是推导过程:
   这里写图片描述

   8.qˉ¹q=1定义非零四元数的逆
    q*q = (w,V)(w,-V)
       = w² - w V + V w - VV
       = w² - (-V·V + V×V
       = w² + |V||V|cos0
       = w² + |V
       = |q
       = ||q||
       = qq*
    
    qˉ¹q=1  => qˉ¹qq*=q*
    qˉ¹ = q*/ ||q||
    qqˉ¹ = qˉ¹q = (1, 0, 0, 0)


二、游戏中的应用

(一)四元数旋转

(1)为什么使用四元数

四元数是3D图形程序员用来表示旋转的数学方法,在许多情况下,与用矩阵表示的旋转相比,用四元数表示的旋转有如下优点:
1. 所需的存储空间比矩阵少;
2. 合并的四元数所需的代数操作少;
3. 对四元数的插值更容易实现,从而产生连续的动画;

(2)先来考虑一个矢量(向量)的旋转

   设矢量V₀旋转θ角变成矢量V₁,|V₀| = |V₁| = r;设垂直于V₀V₁所在平面的转轴方向单位矢量 为℮ᶇ,转动方向与转轴方向遵循右手定则;
  这里写图片描述
   因:V₀·V₁ = r²cosθ
     V₀×V₁ = ℮ᶇ r²sinθ
     (V₀×V₁的结果是一个垂直于V₀V₁所在面的向量,符合右手定则,既方向与℮ᶇ一致,且|V₀×V₁| = |V₀||V₁|sinθ = r²sinθ)

   则:V₁V₀ = -V₁·V₀ + V₁×V₀
        = -V₀·V₁ - V₀×V₁
        = -r²cosθ - ℮ᶇ r²sinθ
        
     V₁ = (-r²cosθ - ℮ᶇ r²sinθ)V₀ˉ¹
       = 1/r²(-r²cosθ - ℮ᶇ r²sinθ)(-V₀
       = (cosθ + ℮ᶇ sinθ)V₀
       
   => V₁ = (cosθ + ℮ᶇ sinθ)V₀
   可以看出,(cosθ + ℮ᶇ sinθ)为一个以℮ᶇ 为旋转轴且旋转量为θ的旋转,乘以V₀后得到V₁,即为绕℮ᶇ轴旋转θ角后的矢量。
   (这个概念很重要!!注意旋转方向,右手法则。但是要注意,这里的情况是℮ᶇ轴与旋转的向量是垂直的,这才成立!!那如果绕不垂直于该轴的旋转呢?继续看下去)
   如果V₀反向旋转,即 cos(-θ) + ℮ᶇ sin(-θ),等同于cosθ + (-℮ᶇ)sinθ,相当于转轴反向。
   

(3)四元数代表的旋转意义

   1. 四元数的三角式与几何意义
   对 q = w+xi+yj+zk做以下变形:
   
     V = xi + yj + zk; 
     |V| = √(x² + y² + z²)
     V = |V|℮ᶇ℮ᶇV的单位向量)
     
     |q| = √(w² + x² + y² + z²)
       = √(w² + |V|²)
    则:
      cosθ = w/|q|  sinθ = |V|/|q|
    这里写图片描述
     q = w + V
       = |q|cosθ + |q|**℮ᶇ**sinθ
       = |q|(cosθ + ℮ᶇ sinθ)
      对比上面的结论  V₁ = (cosθ + ℮ᶇ sinθ)V₀

可以发现,任意一个四元素也表示一个绕℮ᶇ轴的旋转(注意:旋转的向量是与℮ᶇ垂直的,不垂直的情况呢?接下来会分析);其使向量旋转的同时,向量的大小变为原来的|q|倍,这是四元数的几何意义

Like complex numbers, unit quaternion represents a rotation
For 3D rotation:
  w = cos(θ/2)
  (x, y, z) = v = sin(θ/2)℮ᶇ
  
四元数的逆
q  = (w, v) = (cos(θ/2), sin(θ/2)℮ᶇ
qˉ¹ = (w, v)ˉ¹
   = (cos(−θ/2), sin(−θ/2)℮ᶇ)(也就是反过来转,相当于逆)
   = (cos(θ/2), − sin(θ/2)℮ᶇ
   = (w, −v)
   = q*(表示共轭,仅当q为单位四元数时成立)
Using this representation we can determine what the inverse would be. We just negate the angle, move some signs around and we discover that the conjugate is the same as inverse. But as it says, this is only true for unit quaternions.
使用这个表达式,我们可以确定它的逆。我们只需要将角度反向,移动一些符号,我们就能发现,共轭和逆是一样的。当然,这仅当该四元数为单位化时才成立。

    2.矢量旋转的四元数表示
    矢量a可以分解为平行于℮ᶇ的分量和垂直于℮ᶇ的分量,即:a= a⊥ + a//;
    a// = (a·℮ᶇ℮ᶇ
      = -1/2(a℮ᶇ + ℮ᶇa℮ᶇ
      = 1/2(a - ℮ᶇa℮ᶇ
   
    a⊥ = ℮ᶇ×a×℮ᶇ
       = ℮ᶇ×**1/2(**a℮ᶇ - ℮ᶇa
       = 1/2(1/2**℮ᶇ(**a℮ᶇ - ℮ᶇa) - 1/2(a℮ᶇ - ℮ᶇa℮ᶇ
       = 1/2(a + ℮ᶇa℮ᶇ
       
    根据上两个公式结合:
    ℮ᶇa℮ᶇ = a⊥ - a//
   
    如下图所示:
这里写图片描述
   
    矢量a与旋转轴℮ᶇ不垂直时,a℮ᶇ旋转θ角变成适量β,可认为是a的垂直于℮ᶇ的分量a⊥℮ᶇ旋转θ角,然后再与a的平行于℮ᶇ的分量a//合成为β
    如下图所示:
    这里写图片描述
    β = a// +(cosθ+℮ᶇ sinθ)a⊥
      =1/2[(a - ℮ᶇa℮ᶇ)+cosθ(a+℮ᶇa℮ᶇ) + ℮ᶇ sinθ(a+℮ᶇa℮ᶇ)]
      =1/2[(1+cosθ)a + sinθ℮ᶇa - sinθa℮ᶇ + (cosθ -1)℮ᶇa℮ᶇ]

    我们大胆假设该旋转需要乘以两个四元数q₁q₂,即β = q₁aq₂
    =>  β = (w₁ + x ℮ᶇ)a(w₂ + y ℮ᶇ)
        = w₁w₂a + w₁y a℮ᶇ + xw₂ ℮ᶇa + xy ℮ᶇa℮ᶇ
    => ①1/2(1+cosθ) = w₁w₂  ②-1/2sinθ = w₁y   
      ③1/2sinθ = xw₂  ④1/2(cosθ -1) = xy
   
    =>w₁ = w₂ = cos(θ/2);
      x = sin(θ/2);
      y = -sin(θ/2);
      
    => q₁ = cos(θ/2) + sin(θ/2)℮ᶇ
      q₂ = cos(θ/2) - sin(θ/2)℮ᶇ
   
    => β = qaq* = qaqˉ¹ (注意:这是因为其模长=1导致的结果相等)
   
    β = (cos(θ/2),sin(θ/2)℮ᶇa(cos(θ/2),-sin(θ/2)℮ᶇ);
    表示a℮ᶇ轴(根据右手法则)旋转θ角度后,得到β

(二)线性插值及其球型线性插值

由于四元数表示成向量的形式,它们非常适用于插值操作。在对象的动画过程中,插值可以产生对象在已计算好的关键帧之间的中间方向。

(1)简单的线性插值

   最简单的插值是线性插值,对于给定的两个模长为1的四元数q₁q₂,他们的线性插值:
    Lerp(t)= q₁ + (q₂ - q₁)t = (1-t)q₁ + t q₂
   这种情况下,并不会保持q(t)的长度不变,则可以做以下变形:
    Nlerp(t)= [(1-t)q₁ + t q₂] / |(1-t)q₁ + t q₂|;
    这样就能使其保持单位长度。
   这里写图片描述

如图中,令w₁ = w₂ = 0,只考虑其矢量部分V₁V₂
q(t)=(1-t)q₁ + t q₂可如上图所示。
但Lerp(t)存在一个问题,q₁ 和 Lerp(t) 之间的夹角θ的变化速率并不是一个常量,如下图

   这里写图片描述

θ 随 t 变化速率是先增快后减慢,即中间的变化速率最大

(2)球型线性插值

   球型线性插值可以保持四元数的单位长度,也可以保持角速度变化速率为一个常数。
   球型线性插值的方法,其关键点在于其插值操作对象是角度。
   q(t)=a(t)q₁ + b(t)q₂
   a(t)表示q(t)沿q₁方向的分量的长度,b(t)表示q(t)沿q₂方向的分量的长度;
   这里写图片描述  

根据三角形相似的原理,得到如下关系:
这里写图片描述
这是四元数单位化后的简化式:
a(t) = sin[θ(₁-т)]/sinθ;

   这里写图片描述

同理,方法跟上步骤相同,得到简化后的式子:
b(t) = sinθт/sinθ ;

则 :q(t)= a(t)q₁ + b(t)q₂ 变形如下:
   Slerp(t)= q₁ sin[θ(₁-т)]/sinθ + q₂ sinθт/sinθ
   
那么θ角怎么求?
θ = cosˉ¹(q₁·q₂
推导公式如下: (如果有错请指出)
这里写图片描述

上图标示的①和②不懂?请返回上面四元数的旋转意义那里再看一遍;
可以以此公式替代sinθ:
  sinθ = √( 1- (q₁·q₂)² );
注意:q₁q₂的符号选取应保证q₁·q₂>0,这可以保证沿着q₁q₂的最短路径插值;(关于这一点,就不再做推导论证了,有兴趣的朋友可以查阅相关资料)


三、疑问与例子

(一)几个“为什么?”

(1)Why 4 values?

Three values doesn’t produce a division algebra.
3个值无法产生一个除法代数。
Again, a division algebra means that all numbers other than zero have a multiplicative inverse. >Why is a division algebra important? Well, if we want to do rotations, we want to be able to undo them, i.e. take inverses. So having an algebra that handles inverses is necessary.
也就是说,一个可除代数意味着除了0以外的所有数都具有一个乘法逆(例如q的乘法逆为qˉ¹)。为什么说除法逆很重要呢?如果我们想做旋转,我们也还想要还原它,那么就使用逆运算。因此,用一个代数来操纵逆是很有必要的。

(2)what are i, j, k?

Three imaginary axes instead of one.
这个好理解,3个轴,所以i、j、k分别对应三维空间坐标中的三个轴。

(3)为什么四元数不遵循乘法交换律(既q₁q₂q₂q₁)?

Using our familiar vector operations we can multiply two quaternions together as follows. Notice again, that due to the cross product, that this is not commutative.
通过我们熟悉的向量运算,我们可以将两个四元数相乘。注意:由于存在叉乘的原因,它们不能够交换,既不符合交换律。

(4)why half-angles?

q = (w, v) = (cos(θ/2), sin(θ/2)℮ᶇ)表示绕℮ᶇ关于右手定则旋转θ角度。关于为什么是θ/2 而不是θ的问题,这个……很难直白的说,但是这个在上文的《四元数代表的旋转意义》一节中有讲解。

(5)What does qpqˉ¹ do?

这是对一个四元数p根据q进行旋转后得到的新的四元数。这个p是实部为0的四元数,即将一个三维空间中的向量V转化为四元数p = (0,V);
那么,为什么要左乘q和右乘qˉ¹呢? 同样,这个在上文的《四元数代表的旋转意义》一节中有对这一公式的来源做推导,可以仔细看看这一节的内容。

(二)举个栗子

现在简单的举一个旋转的操作流程,对一个已知向量,如何根据一个旋转四元数做旋转,得到旋转后的向量。 (我的翻译不太行,所以我会把其英文也贴出来)

Have vector p, unit quaternion q  
● Treat p as quaternion p=(0,p)  
● 3D rotation of p by q is  
 p’= qpqˉ¹
● Boils down to
 p’= p + 2w(v × p) + 2(v × (v × p))
 w = cos(θ/2)
 (x, y, z) = v = sin(θ/2)℮ᶇ

你有一个向量p,和一个单位四元数q
● 将向量p转化成一个四元数p=(0,p
p通过q的3D旋转为:
 p’= qpqˉ¹
●归总:
 p’= p + 2w(v × p) + 2(v × (v × p))
 w = cos(θ/2)
 (x, y, z) = v = sin(θ/2)℮ᶇ

p’定是一个纯四元数,即其实部w为0,那么,向量p’就是向量p根据一个单位四元数q旋转后的得到新向量了;
表示为向量p绕旋转轴℮ᶇ,根据右手定则,旋转θ角度,得到旋转后的新向量p’

这里有几个点需要注意:
 1.用于旋转的四元数,每个分量的范围都在(-1,1);
 2.每一次旋转实际上需要两个四元数的参与,即q和q*;
 3.所有用于旋转的四元数都是单位四元数,即它们的模是1;

  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值