了解四元数之美_四元数

一、了解四元数

在本文中,我将尝试以一种易于理解的方式来解释四元数的概念。我将说明您如何可视化四元数,并说明可应用于四元数的不同操作。我还将比较矩阵,欧拉角和四元数的应用,并尝试解释何时要使用四元数代替欧拉角或矩阵,何时不使用。

内容

 

了解四元数之美_四元数_02

介绍

在计算机图形学中,我们使用变换矩阵来表示空间中的位置(平移)及其在空间中的方向(旋转)。可选地,单个变换矩阵也可以用于表示对象的比例或“剪切”。我们可以将转换矩阵视为“基本空间”,如果您将向量或点(甚至另一个矩阵)乘以转换矩阵,则可以将该向量,点或矩阵“转换”为该矩阵表示的空间。

在本文中,我将不讨论转换矩阵的详细信息。有关转换矩阵的详细说明,您可以参考我以前的文章《矩阵》

在本文中,我想讨论一种使用四元数描述空间中物体(旋转)方向的替代方法。

四元数的概念由爱尔兰数学家William Rowan Hamilton爵士于1843年10月16日星期一在爱尔兰都柏林实现。汉密尔顿和他的妻子一起去爱尔兰皇家艺术学院的途中,当他经过布劳姆大桥上的皇家运河时,他突然意识到他立刻在桥的石头上雕刻了出来。

了解四元数之美_四元数_03

了解四元数之美_四元数_04

威廉·罗恩·汉密尔顿(William Rowan Hamilton)位于皇家运河布鲁姆桥上的纪念匾,以纪念他发现四元数乘法的基本公式。

复数

在我们完全理解四元之前,我们必须首先了解它们的来源。四元数的根基于复数系统的概念。

除了众所周知的数字集(NaturalIntegerRealRational),复数系统还引入了一组新的数字,称为虚数。发明了虚数来求解某些无解的方程,例如:

了解四元数之美_四元数_05

为了解决该表达式,我们必须声明了解四元数之美_游戏引擎开发_06,我们知道这是不可能的,因为任何数字(正数或负数)的平方始终为正。

数学家通常不能接受表达式没有解,因此发明了一个新术语,称为虚数,可以用来解这些方程。

虚数的形式为:

了解四元数之美_游戏引擎开发_07

不要试图真正理解这个术语,因为没有逻辑上的理由说明它存在的原因。我们只需要接受 i  的平方等于-1.

虚数集可以用了解四元数之美_游戏引擎开发_08表示。

复数集(由符号C表示)是实数和虚数的总和,其形式为:

了解四元数之美_游戏引擎开发_09

也可以说所有实数都是b=0的复数,所有虚数都是复数a=0

复数加减法

可以通过增加或减少实部和虚部来增加和减少复数。

加法:

了解四元数之美_四元数_10

减法:

了解四元数之美_四元数_11

复数乘以标量

通过将复数的每一项乘以标量,将复数乘以标量:

了解四元数之美_四元数_12

复数乘积

复数也可以通过应用常规代数规则相乘。

了解四元数之美_四元数_13

复数平方

复数也可以通过乘以平方来求平方:

了解四元数之美_四元数_14

共轭复数

共轭复数是否定的虚部的复数,并表示为了解四元数之美_四元数_15了解四元数之美_游戏引擎开发_16

了解四元数之美_游戏引擎开发_17

复数与其共轭的乘积给出了特殊的结果。

了解四元数之美_四元数_18

复数的绝对值

我们可以使用复数的共轭来计算复数的绝对值(或范数大小)。复数的绝对值是复数乘以其共轭的平方根,并表示为|z|

了解四元数之美_游戏引擎开发_19

两个复数的商

为了计算两个复数的商,我们将分子和分母乘以分母的复共轭。

了解四元数之美_四元数_20

i 的幂

如果我们说了解四元数之美_游戏引擎开发_21那么也应该有可能将提升 i 到其他幂。

了解四元数之美_四元数_22

如果我们继续写这个序列,我们会看到一个模式出现了解四元数之美_四元数_23

在幂指数负增长的时候一个相似的情况出现了。

了解四元数之美_四元数_24

您之前可能已经在数学上看到过类似的模式,但是形式为(x,y,−x,−y,x,…),它是通过在2D笛卡尔平面上逆时针旋转点90°而产生的(x,−y,−x,y,x,…)是通过在2D笛卡尔平面上顺时针旋转点90°生成的。

了解四元数之美_游戏引擎开发_25

                                                                     笛卡尔平面

复杂平面

我们还可以通过在水平轴上映射实数部分在垂直轴上映射虚数部分,在称为复杂平面的2D网格中映射复数。

了解四元数之美_四元数_26

                                                                           复杂平面

如前面的序列所示,可以说,如果将复数乘以 i,则可以将复数以90°的增量旋转通过复数平面。

让我们看看这是不是真的。我们将在复平面上取任意点p

了解四元数之美_游戏引擎开发_27

我们让 p 乘以i 得到q

了解四元数之美_四元数_28

q 乘以 i 赋值给 r

了解四元数之美_四元数_29

r 乘以 i 赋值给 s

了解四元数之美_四元数_30

s 乘以 i 赋值给 t

了解四元数之美_游戏引擎开发_31

正是我们从(p)开始。如果将这些复数绘制在复数平面上,则会得到以下结果。

了解四元数之美_游戏引擎开发_32

                                                                                     复平面上的复数

我们也可以通过将复数乘以-i 在复平面中顺时针旋转。

转子

我们还可以通过定义以下形式的复数来在复杂平面中执行任意旋转:

了解四元数之美_游戏引擎开发_33

将任何复数乘以转子q 即可得出以下通式:

了解四元数之美_游戏引擎开发_34

也可以用矩阵形式编写:

了解四元数之美_游戏引擎开发_35

这是使复平面中的任意点绕原点逆时针旋转的方法。

四元数

有了复数系统和复平面的知识,我们可以通过在 i 之外向我们的数系统添加两个虚数,将其扩展到3维空间。

表达四元数的一般形式是

了解四元数之美_四元数_36

根据汉密尔顿的著名表达:

了解四元数之美_游戏引擎开发_37

了解四元数之美_游戏引擎开发_38

您可能已经注意到 i  ,j 和k 之间的关系与单位笛卡尔向量的叉积规则非常相似:

了解四元数之美_四元数_39

汉密尔顿还认识到虚数 i , j  和 k  可以用来表示三个笛卡尔单位向量 i ,j 和 k 具有相同的虚数属性,因此了解四元数之美_游戏引擎开发_40

了解四元数之美_游戏引擎开发_41

                                                                                              可视化属性 ij,jk,ki

上图显示了由 i , j 和 k 表示的笛卡尔单位向量之间的关系。

四元数作为有序对

我们还可以将四元数表示为有序对:

了解四元数之美_游戏引擎开发_42

其中 v 也可以由其各个组成部分表示:

了解四元数之美_游戏引擎开发_43

使用此表示法,我们可以更轻松地显示四元数和复数之间的相似性。

四元数的加减

四元数可以和复数一样进行相加或相减:

了解四元数之美_游戏引擎开发_44

四元数乘法

我们还可以表示两个四元数的乘积:

了解四元数之美_游戏引擎开发_45

从而得到另一个四元数。如果我们用有序对(也称为四元数单位)替换前面表达式中的虚数i、j和k,

了解四元数之美_游戏引擎开发_46

把这个表达式展开成有序对的和,得到:

了解四元数之美_四元数_47

如果我们与四元数单位相乘并提取公共向量分量,我们可以这样重写此方程:

了解四元数之美_四元数_48

这个方程给出了两个有序对的和。第一个有序对是实四元数,第二个是纯四元数。这两个有序对可以组合成一个有序对:

了解四元数之美_四元数_49

如果我们替换,

了解四元数之美_游戏引擎开发_50

我们得到:

了解四元数之美_四元数_51

这是四元数积的一般方程。

实四元数

实四元数是向量项为0的四元数

了解四元数之美_四元数_52

两个实四元数的乘积是另一个实四元数:

了解四元数之美_游戏引擎开发_53

它类似于包含零虚项的两个复数的乘积。

了解四元数之美_游戏引擎开发_54

四元数乘以标量

我们也可以将四元数乘以一个标量,这个标量应该遵守以下规则:

了解四元数之美_四元数_55

我们可以使用上面所示的乘积或实四元数将四元数乘以标量作为实四元数来确认这一点:

了解四元数之美_四元数_56

纯四元数

类似于四元数,汉密尔顿还将四元数定义为标量项为零的四元数:

了解四元数之美_四元数_57

或者,写在其组成部分中:

了解四元数之美_四元数_58

我们也可以取两个纯四元数的乘积:

了解四元数之美_四元数_59

根据上面所示的四元数积规则。

四元数的加法形式

我们还可以将四元数表示为四元数和四元数的一部分:

了解四元数之美_四元数_60

单位四元数

给定一个任意向量v,我们可以用它的标量大小和方向来表示这个向量:

了解四元数之美_四元数_61

把这个定义和纯四元数的定义结合起来,可以得到:

了解四元数之美_四元数_62

我们还可以描述一个具有零标量和单位向量的单位四元数:

了解四元数之美_四元数_63

四元数的二元形式

我们现在可以将单位四元数的定义和四元数的加法形式结合起来,我们可以创建一个四元数的表示法,它类似于用于描述复数的符号:

了解四元数之美_游戏引擎开发_64

这为我们提供了一种表示与复数非常相似的四元数的方法:

了解四元数之美_四元数_65

共轭四元数

可通过对四元数的向量部分求反来计算四元数共轭:

了解四元数之美_游戏引擎开发_66

四元数与其共轭的乘积给出:

了解四元数之美_游戏引擎开发_67

四元数范数

如果您从复数范数的定义中回想起:

了解四元数之美_游戏引擎开发_68

类似地,四元数的范数(或大小)定义为:

了解四元数之美_游戏引擎开发_69

它允许我们将四元数的范数表示为:

了解四元数之美_游戏引擎开发_70

四元数归一化

根据四元数范数的定义,我们可以用它来规范化四元数。一个四元数被| q |整除:

了解四元数之美_游戏引擎开发_71

例如,让我们规范化四元数:

了解四元数之美_四元数_72

首先,我们必须计算四元数的数:

了解四元数之美_游戏引擎开发_73

然后,我们必须将四元数除以四元数的范数,以计算归一化的四元数:

了解四元数之美_游戏引擎开发_74

四元数的逆

四元数的逆表示为q-1。为了计算四元数的逆,我们取四元数的共轭并除以范数的平方:

了解四元数之美_四元数_75

为了说明这一点,我们可以认为,根据四元数的逆的定义:

了解四元数之美_游戏引擎开发_76

并将两边乘以四元数的共轭得到:

了解四元数之美_四元数_77

通过替换,我们得到:

了解四元数之美_四元数_78

对于范数为1的单位范数四元数,我们可以这样写:

了解四元数之美_四元数_79

四元数点积

与向量点积相似,我们也可以通过乘以相应的标量部分并将结果相加来计算两个四元数之间的点积:

了解四元数之美_游戏引擎开发_80

我们还可以使用四元数点积来计算四元数之间的角度差:

了解四元数之美_游戏引擎开发_81

对于单位范数四元数,我们可以简化等式:

了解四元数之美_游戏引擎开发_82

旋转

如果您还记得,我们定义了复数的一种特殊形式,称为转子,它可用于通过二维复平面旋转点,如下所示:

了解四元数之美_四元数_83

然后,由于其与复数的相似性,应该有可能这样表达一个四元数,该四元数可用于旋转3D空间中的点:

了解四元数之美_游戏引擎开发_84

让我们通过计算四元数q和向量p的乘积来检验这个理论是否成立。首先,我们可以用以下形式将p表示为纯四元数:

了解四元数之美_游戏引擎开发_85

q是单位范数四元数的形式:

了解四元数之美_游戏引擎开发_86

然后,

了解四元数之美_游戏引擎开发_87

我们看到结果是一个具有标量部分和向量部分的通用四元数。
让我们首先考虑“特殊”情况,其中p垂直于了解四元数之美_游戏引擎开发_88在这种情况下,点积项了解四元数之美_四元数_89,结果变成纯四元数:

了解四元数之美_四元数_90

在这种情况下,为了使p绕了解四元数之美_游戏引擎开发_88旋转,我们只需将了解四元数之美_四元数_92了解四元数之美_游戏引擎开发_93代入。

了解四元数之美_四元数_94

例如,让我们绕z轴旋转一个向量p 45°然后我们的四元数q是:

了解四元数之美_游戏引擎开发_95

让我们取一个向量p,它依附于p垂直于k的特殊情况:

了解四元数之美_四元数_96

现在让我们计算qp的乘积:

了解四元数之美_游戏引擎开发_97

从而得到一个纯四元数,它绕k轴旋转45°。我们还可以确认,结果向量的大小保持不变:

了解四元数之美_四元数_98

这正是我们所期望的结果!


我们可以通过下面的图片将其可视化:

了解四元数之美_游戏引擎开发_99

                                                                               四元数旋转(1)

 

现在让我们考虑一个与p不正交的四元数。如果我们将四元数的向量部分指定为距p 45°的偏移,我们得到:

了解四元数之美_游戏引擎开发_100

 

把向量p乘以q,我们得到:

了解四元数之美_游戏引擎开发_101

代入了解四元数之美_游戏引擎开发_102了解四元数之美_游戏引擎开发_103得出:

了解四元数之美_游戏引擎开发_104

 

它不再是一个纯四元数,也没有旋转45度,向量的范数也不再是2(相反,它已经减少到了解四元数之美_四元数_105).

这个结果可以通过图像可视化。

了解四元数之美_游戏引擎开发_106

                                                                            四元数旋转(2)

从技术上讲,在三维空间中表示四元数p′是不正确的,因为它实际上是一个4D向量!为了简单起见,我将只可视化四元数的矢量分量。

然而,一切都没有失去。汉密尔顿认识到(但没有发表)如果我们把qp的结果乘以q的逆

然后得到一个纯四元数,并保持向量分量的范数。让我们看看能否把这个应用到我们的例子中。

首先,让我们计算q-1:

了解四元数之美_游戏引擎开发_107

了解四元数之美_四元数_108代入得:

了解四元数之美_游戏引擎开发_109

并结合qp和q-1的先前值给出:

了解四元数之美_四元数_110

这是一个纯四元数,结果的范数是:

了解四元数之美_四元数_111

 

与p相同

所以向量的范数保持不变。

下图显示了旋转的结果。

了解四元数之美_四元数_112

 

                                                                                         四元数旋转(3)

 

所以我们可以看到结果是一个纯四元数,并且初始向量的范数保持不变,但是向量旋转了90度而不是45度,这是期望值的两倍!因此,为了正确地将向量p绕任意轴v^旋转一个角θ,我们必须考虑半角并构造以下四元数:

了解四元数之美_游戏引擎开发_113

这是旋转四元数的一般形式!

四元数插值

在计算机图形学中使用四元数的最重要原因之一是四元数非常善于表示空间旋转。四元数克服了困扰3D空间中其他旋转点方法的问题,例如Gimbal锁定,当您用欧拉角表示旋转时会遇到此问题。

使用四元数,我们可以定义几种表示3D空间中旋转插值的方法。我将研究的第一种方法称为SLERP,该方法用于在两个方向之间平滑地插入点。第二种方法是SLERP的扩展,称为SQAD,用于对定义路径的一系列定向进行插值。

SLERP

SLERP代表球面线性插值。SLERP提供了一种平滑地插值两个方向上的点的方法。

我将第一个方向表示为q1,第二个方向表示为q2。插值点用p表示,插值点用p′表示。当t=0时,插值参数t将从q1插值到t=1时的q2。

标准线性插值公式为:

了解四元数之美_游戏引擎开发_114

应用此公式的一般步骤是:

  • 计算p1和p2之间的差
  • 把差额的小数部分计算出来。
  • 通过两点之间的分数差调整原始值。


我们可以使用相同的基本原理在两个四元数方向之间进行插值。

四元数差分

第一步要求我们必须计算 q1 和 q2 之间的差。关于四元数,这等效于计算两个四元数之间的角度差。

了解四元数之美_游戏引擎开发_115

四元数指数

下一步是把差额的小数部分去掉。我们可以将四元数的小数部分提升到一个值在[0…1]范围内的幂。

四元数指数化的一般公式是:

了解四元数之美_四元数_116

其中四元数的指数函数由下式给出:

了解四元数之美_游戏引擎开发_117

四元数的对数由下式给出:

了解四元数之美_游戏引擎开发_118

 

当t=0时,我们有:

了解四元数之美_游戏引擎开发_119

当t=1时,我们有:

了解四元数之美_游戏引擎开发_120

四元数的分数差分

为了计算插值的角旋转,我们用q1和q2之间的差的小数部分来调整原始方向q1。

了解四元数之美_游戏引擎开发_121

这是四元数球面线性插值的一般形式。然而,这并不是实际中常用的SLERP方程的形式。


我们可以应用一个类似的公式来执行向量到四元数的球面插值。向量球面插值的一般形式定义为:

了解四元数之美_四元数_122

这在下图中是可视化的。

了解四元数之美_四元数_123

                                                                                       四元数插值

此公式可以未经修改应用于四元数:

了解四元数之美_四元数_124

通过计算q1和q2之间的点积可以得到角θ。

了解四元数之美_四元数_125

 

注意事项

 

执行过程中必须考虑到两个问题。

首先,如果四元数点积的结果是负值,那么得到的插值将绕着4D球体“长途跋涉”,这不一定是我们想要的。为了解决这个问题,我们可以测试点积的结果,如果它是负的,那么我们可以否定其中一个方向。对四元数的标量和矢量部分求反不会改变它所表示的方向,但这样做可以保证旋转将应用于“最短”路径。

另一个问题是当q1和q2之间的角差很小时,sinθ变为0。如果发生这种情况,那么我们除以sinθ就会得到一个未定义的结果。在这种情况下,我们可以回到使用q1和q2之间的线性插值。

SQUAD

就像SLERP可以用来计算两个四元数之间的插值一样,SQUAD(球面和四边形)也可以用来在旋转路径上平滑地进行插值。


如果我们有四元数序列:

了解四元数之美_游戏引擎开发_126

我们还定义了“helper”四元数(si),我们可以考虑一个中间控制点:

了解四元数之美_四元数_127

然后沿子曲线的方向定义为:

了解四元数之美_四元数_128

时间t由以下给出:

了解四元数之美_游戏引擎开发_129

结论

尽管很难理解,四元数比使用矩阵或欧拉角来表示旋转提供了一些明显的优势。

  • 利用SLERP和SQUAD进行四元数插值,为空间方向间的平滑插值提供了一种方法。
  • 使用四元数的旋转连接比组合以矩阵形式表示的旋转更快。
  • 对于单位范数四元数,则通过减去四元数的矢量部分来获得旋转的逆。如果矩阵不是正交的,则计算旋转矩阵的逆要慢得多(如果是,则只是矩阵的转置)。
  • 将四元数转换为矩阵的速度略快于欧拉角。
  • 四元数只需要4个数字(如果它们是标准化的,则需要3个数字)。实际部分可以在运行时计算)以表示矩阵至少需要9个值的旋转。

然而,尽管有利于使用四元数的所有优点,也有一些缺点。

  • 由于浮点舍入误差,四元数会变得无效,但是可以通过重新标准化四元数来解决此“错误蠕变”问题。
  • 使用四元数的最重要的威慑因素可能是它们很难理解。我希望阅读本文后能解决此问题。

有几个数学库可以实现四元数,而其中一些库可以正确实现四元数。根据我的个人经验,我发现GLM(OpenGL数学库)是一个很好的数学库,具有很好的四元数实现。如果您对在自己的应用程序中使用四元数感兴趣,这是我推荐的库。

下载演示

我创建了一个小型演示,演示了如何使用四元数旋转空间中的对象。该演示是使用Unity 3.5.2 创建的,您可以免费下载并查看演示脚本文件。该zip文件还包含Windows二进制可执行文件,但是使用Unity时,您还可以生成Mac应用程序(Unity 4也引入了Linux版本)。

了解Quaternions.zip

参考

了解四元数之美_四元数_130

了解四元数之美_四元数_131

四元数–维基百科

四元数和空间旋转–维基百科