4.3 Quaternions
虽然四元数早在1843年就由William Rowan Hamilton先生发明出来用于表示复数的扩展,但是直到1985年才由Shoemake[1176]把四元数引入到了计算机图形学领域。四元数是构建具有强大功能的变换操作的一个有力工具,而且在某些方面,四元数是比欧拉角度和矩阵更好的计算方式,特别是在旋转操作和方位计算方面。给定一个 轴&角度 的表示形式,转变成一个四元数或从四元数转变成原来的形式是直截了当的,而使用欧拉角度则无法在任何方向进行转换。四元数可以用于稳定并不断的确定方位的插值运算,而这是使用欧拉角度无法完成的。
复数包含一个实部和一个虚部。每一个部分由两个实数表示,其中第二个实数通过与 −1−−−√ 相乘。类似的,四元数具有四个部分。前三个部分的值与旋转轴密切相关,因为旋转的角度会影响所有部分的值(4.3.2节有更多相关的内容)。每一个四元数由4个实数表示,每个实数对应于一个不同的部分。由于四元数具有四个分量,我们选择使用向量的形式表示它们,但是与向量不同的是,在记号上加一个帽子: q^ 。首先我们会讨论一些关于四元数的数学背景知识,然后用于构建一些有趣的,实用的变换运算。
4.3.1 Mathematical Background
我们从描述一个四元数的定义开始。
Definition. 可以使用下面的方法定义四元数
q^
,所有的定义都同等的。
其中变量
qw
称为四元数
q^
的实部,虚部为
qv
,并且
i
,
对于四元数的虚部
从该公式中可以看出,我们同时使用了叉积和点积计算两个四元数的乘积。有了四元数的定义之后,我们就可以定义四元数的加法,共轭,范数,以及单位化运算:
在对n(\hat{\mathbf{q}}) = \sqrt{\hat{\mathbf{q}}\hat{\mathbf{q}}^*}进行简化(结果如上)之后,虚部都抵消了且只剩下一个实部。四元数的规范化有时也可以表示为|\hat{\mathbf{q}}| = n(\hat{\mathbf{q}})[808]。由以前运算的结果可以推导出四元数的乘法倒数,表示为
q^−1
。倒数必须满足公式
q^−1q^=q^q^−1=1
(这正是乘法倒数的通用性质)。由四元数规范化运算的定义可以推出以下公式:
由此可以得到如下的乘法倒数公式:
四元数的求导公式使用了标量乘法,这是由公式4.29中的乘法运算推导出来的: sq^=(0,s)(qv,qw)=(sqv,sqw) ,并且 q^s=(qv,qw)(0,s)=(sqv,sqw) ,也就是说标量乘法满足交换律。
由四元数的定义可以推导出以下的运算法则:
一个四元数
q^=(qv,qw)
为单位四元数,也就是说
n(q^)=1
。由此可以把
q^
写成如下形式:
对于某些三维向量
uq
,有
∥uq∥=1
,因为
有且仅有 uq⋅uq=1=∥uq∥2 。在下一节我们将会看到,单位四元数非常适合用于高效的创建旋转和定向运算。但在些之前,将会介绍关于四元数的一些额外操作。
对于复数,一个二维的单位向量可以写成
cosϕ+isinϕ=eiϕ
。而对于复数,使用同样的方法表示为
由公式4.38可以得到单位四元数的对数和指数运算公式:
4.3.2 Quaternion Transforms
我们现在开始研究四元数集的一个子类,单位四元数,即那些具有单位长度的四元数。有关单位四元数的最重要的性质是它们可以表示任意的三维旋转,并且这种表示方式极其紧凑简单。
现在我们描述四元数对于旋转和定向操作如此实用的原因。首先把一个点或向量
p=(px py pz pw)T
4个坐标值存储到一个四元数
p^
的四个分量中,并假设有一个单位四元数
q^=(sinϕuq,cosϕ)
。则有
把四元数 p^ (也就是点 p )围绕轴 uq 旋转 2ϕ 度。需要注意的是,由于 q^ 是一个单位四元数,有 q^−1=q^∗ 。图4.8中演示了该旋转操作,显示这种方法可以用于围绕任意轴旋转。
图4.8 使用单位四元数
q^=(sinϕuq,cosϕ)
表示旋转变换的示例。该变换表示围绕轴
uq
旋转
2ϕ
弧度。
四元数 q^ 任何非0的多个实部也可以表示同样的变换,这意味着 q^ 和 −q^ 表示相同的旋转操作。也就是说对轴 uq 及实部 qw 取反,会创建一个与原始四元数旋转结果完全一样的四元数。同样还意味着从一个矩阵中提取出四元数可以是 q^ 或者 −q^ 。
给定两个单位四元数
q^
和
r^
,对四元数
p^
(可以用于表示点
p
) 首先使用
q^
再使用
r^
的串联运算,如果公式4.41所示:
其中 c^=r^q^ 是一个单位四元数,表示单位四元数 q^ 和 r^ 的串联。
Matrix Conversion
由于一些系统使用硬件的方式实现矩阵乘法,并且这种矩阵乘法比公式4.40更加高效,因此我们需要一种方法用于把一个四元数变换成一个矩阵,反之亦然。把四元数
q^
转换成矩阵
Mq
,可以使用公式4.42表示
其中标量为 s=2/n(q^) 。对于单位四元数,公式4.42可以简化为
使用四元数构建了矩阵之后,没有任何三角函数需要计算了,因此在实际运算过程中这种变换过程是非常高效的。
反过来,从一个正交矩阵
Mq
变换为单位四元数
q^
则需要更多运算。该运算过程的关键是由公式4.43中的矩阵得到的不同点:
这些公式所表示的含义是,如果 qw 是已知的,就可以计算向量 vq 的值,因此可以推导出 q^ 。使用如下公式可以计算矩阵 Mq 的迹
由此可以得到如下单位四元数的转换公式:
为了得到一个数值稳定的例程,需要避免除以较小的数。因此,首先设置
t=q2w−q2x−q2y−q2z
,由此可以得到如下公式
也就是说最大的 m00,m11,m22 和 u 值反过来可以确定
然后使用上面适用的公式计算 qx,qy 和 qz 的最大值,之后再使用公式4.44计算四元数 q^ 的其余分量值。幸运是已经有相关的代码用于转换的计算,见本章末尾的Further Reading and Resources。
Spherical Linear Interpolation
Spherical Linear Interpolation(球面线性插值)是指,给定两个单位四元数 q^ 和 r^ ,以及一个参数 t∈[0,1] ,计算一个插值四元数的操作。比如在处理动画物体时这种操作非常实用。但是对于相机朝向的插值运算该操作并不实用,因为相机的“向上方向”的向量在插值过程中会发生倾斜,通常产生一种令人不快的效果。
这种插值操作的代数形式可以使用如下的组合四元数
s^
表示:
但是对于使用软件实现来说,使用以下的形式更合适,其中 slerp 表示球面线性插值:
要计算该公式中所需要的 ϕ 值,可以使用如下论据: cosϕ=qxrx+qyry+qzrz+qwrw [224]。对于任意的 t∈[0,1] ,slerp函数用于计算插值的两个四元数从 q^(t=0) 到 r^(t=1) 一起构成了四维单位球面上的最短圆弧。该弧线位于由 q^ 、 r^ 及球心所有的平面,与四维单位球的相交形成的圆圈上。如图4.9所示。由些计算得到的旋转四元数以恒定的速度围绕一个固定轴旋转。这种具有恒定速度的旋转曲线, 加速度为0,称为 geodesic 曲线[263]。
slerp函数非常适用于在两个朝向向量之间进行插值,并且计算结果非常稳定(保持固定轴,恒定速度)。在使用多个欧拉角度进行插值时无法达到这种运算效果。在实际运算过程中,直接执行slerp运算需要调用大量的三角函数,是一种高计算成本的操作。为此,Li[771,772]提出改进的方法,在不牺牲任何精度的情况下可以更快速的计算slerps值。
当有多个表示朝向的四元数可以用时,比如 q^0 , q^1 , ⋅⋅⋅ , q^n−1 ,并且我们要从 q^0 到 q^1 再到 q^2 进行插值,依此类推,直接到 q^n−1 ,可以使用一连串的slerp运算。假设现在要计算 q^i ,我们将会使用 q^i−1 和 q^i 作为slerp的参数。计算完 q^i 之后,就使用 q^i 和 q^i+1 作为下一个slerp运算的参数。这会导致在对朝向向量进行插值过程中出现急剧的变动,如图4.9所示。这种方法类似于对多个点进行线性插值;详见原书578页图13.2的右上图。一些读者在阅读第13章有关样条曲线的描述之后可能会回过头来学习以下段落。
一种更好的插值计算方法是使用某种样式的样条曲线。首先我们引入介于
q^i
和
q^i+1
之间的四元数
a^i
和
a^i+1
。然后使用
q^i
,
a^i
,
a^i+1
和
q^i+1
组成的四元数集定义三次球面插值运算。令人惊奇的是,使用如下的公式可以计算这些额外的四元数[294]:
其中 q^i 和 a^i 用于对四元数进行球面插值,使用公式4.52所示的光滑的三次样条曲线:
如上公式所示, slerp 函数由多次重复使用slerp进行球面插值运算构成(详见第13章13.1.1节有关对多个点进行重复线性插值的讲解)。插值将会在初始的朝向四元数 q^i,i∈[0,⋅⋅⋅,n−1] 之间进行传递,但是不会在 a^i 中传递,这些新引入的四元数用于表示初始四元数的切线方向。
插值将通过传递
初始方向 ˆqi,我 ∈ [0,…,n−1],但不是通过 ˆai — — 这些都是
用于指示在初始取向的切线方向