资料援引
四元数与三维旋转 Krasjet*
复数的物理意义是什么?
视频-球极平面投影
圆柱投影:墨卡托、横轴墨卡托和米勒
复球面——球极坐标平面投影
了解地图投影
Understanding Quaternions
知乎-复数、复平面、旋转向量
轨迹规划之姿态插补
轨迹规划之位置插补
复数的物理意义
我们都知道:i2 = −1
那么可得:4∗i∗i=−4,其物理意义就是4在数轴上旋转了180度。
那么可推断出4*i就是旋转了90度。

不考虑i时,数的加减乘除仅能在实数轴上做运动,这是一维运动,而开始考虑i时,就诞生了一条虚数轴,这就允许点脱离线的限制,而存在于面上,这是二维运动。
可能读到这里你会觉得,唉?没什么了不起的啊,(x,y)也可以描述一个二维平面上的点啊。但是x、y是两个数描述一个二维点,而复数则是一个数描述一个二维点!
乘i即将向量转动90度:

首先了解两个概念:
- 模:复数的模等于复数描述的点到原点的距离。
- 辐角:复数的辐角等于复数描述的向量和
x轴(实数轴)正半轴的夹角。
那么再来观察任意两个复数的乘积、模、辐角,可以发现:
- 两个复数乘积的模 = 两个复数模的乘积
- 两个复数乘积的辐角 = 两个复数辐角的和

球面投影
球面投影是指将球体表面上的点投影到一个平面的方法,主要有圆柱投影和球极平面投影两类方法。
圆柱投影
圆柱投影是一种将地球表面投影到一个圆柱体上,然后将圆柱体展开成平面的一种地图投影方法。根据圆柱体与地球的相对位置(如相切、相割)和投影特性的不同,圆柱投影可以分为多种类型,其中航海、航空等领域广泛应用的墨卡托投影就是其中的一种。
圆柱面包围投影球有三种可能的方式:
Equatorial:赤道模式,圆柱体的横截面与投影球的纬线平行
Transverse:横向模式,圆柱体的横截面与投影球的经线平行
Oblique:倾斜模式,包围方式为其它角度

问:为什么将球面展开成平面就是 2:1 ?
将球面展开成平面时,2:1 的比例是为了尽量减少变形和失真。这种展开方式通常被称为等距矩形投影( Equirectangular Projection) :
- 保持经纬比例关系:经度范围是
0到360度(2π弧度),纬度范围是-90度到90度(π弧度)。因此,矩形的宽度是高度的两倍,即2:1的比例。
- 减少 失真:虽然任何将球面展开成平面的投影都会引入某种形式的失真,但等距矩形投影在保持经纬度比例的同时,尽量减少了失真。这使得它在全景图和环境贴图中非常常用。
- 广泛应用:等距矩形投影广泛应用于全景图、虚拟现实(VR)、环境贴图等领域,因为它能够较好地表示球面上的信息,并且易于处理和渲染。
球极平面投影
- 取一球体,让它在坐标系原点与平面相切,相切点是它的南极:

- 将每个复数对应于球面上一点(除了北极,也就是投影的终点,没有复数与之对应,因为它对应于无穷远处):

全部对应的结果:

为什么北极无法被投影在平面,只能对应无穷远?
首先复习一下两点式方程:
x0−x1x−x0=y0−y1y−y0=z0−z1z−z0
北极点三维坐标为(0,0,1),设球面上另一点的坐标为(x1,y1,z1),可得两点式方程:
−x1x=−y1y=1−z1z−1
球的投影在二维平面上,因此需要令z=0 ,可以解得⎩⎨⎧x=1−z1x1y=1−z1y1
可以得到表示三维球面坐标信息的复数方程式w = x + yi
其中x和y对应二维坐标系中坐标,x1、y1和z1对应三维坐标系中的坐标,由于分母不能为0,因此只有在z1=1时无法完成从三维坐标到二维坐标的转换,而整个球体只有北极点的z1为1。
-
这样球面就是一条复射影直线,它用一个复数表达式(w = x + yi)来存储一个点的集合,集合中的点与球面上的位置一一对应,这些点组成了一根线,该线在二维平面上描述了一个三维球体,而不需要XYZ三维坐标来表达一个球体。
- 直线:数学上称点的集合为直线。
- 复直线:描述点的数都是复数。
- 射影:通过射影得到三维坐标在平面上对应的二维坐标,球上越靠近北极的点投影在平面上就离原点越远,直至趋近无穷。
球极平面投影完全保留了角度信息,但不维持面积不变,特别是在射影点附近。
二维空间的复数与旋转
欧拉公式
在体验复数是怎样实现二维空间旋转之前,首先有请宇宙第一耍帅公式欧拉公式隆重登场:

称它为宇宙第一耍帅公式是因为它的特殊形式——当x等于Pi的时候:

它将数学里最重要的几个数字联系到了一起:两个超越数:自然对数的底e,圆周率π;两个单位:虚数单位i和自然数的单位1;以及被称为人类伟大发现之一的0。
二维平面旋转公式(复数积型)
- 对于复数 z=a+bi,a 对应实数轴上的距离,b 对应虚数轴上的距离,该复数的模长 r :
r=a2+b2
- 假设在平面上一个向量旋转的角度为
θ,z=a+bi 可以表达为:
z=rcosθ+i×rsinθ=r(cosθ+isinθ)
- 我们称括号中的内容为单位复数旋转因子,并用 q 表示:
q=cosθ + isinθ
cosθ对应实数轴上的值,sinθ对应虚数轴上的值,以动图表示旋转因子与对应角度的关系:

- 假设被转动的向量以复数形式表达为p=a+bi,将被转动的向量乘以这个单位复数旋转因子:
pq=(a+bi)(cosθ+isinθ)
- 得到被转动向量旋转
θ后的复数p',也就是二维平面旋转公式(复数积型):
p′=pq=p(cosθ+isinθ)=acosθ−bsinθ+(asinθ+bcosθ)i
- 举个例子,比如被转动向量p=2+0i,旋转角度为
45度,所以最终得到的复数为:
p′=2+2i
- 也就是说起点坐标为(0,0),终点坐标为(2,2)的向量,旋转
45度之后终点坐标为(2,2)。
因此将二维平面上一个向量(a,b)看作复数a+bi,再乘以单位复数旋转因子就可以实现旋转某个角度。
二维平面旋转公式(指数型/极坐标型)
- z=r(cosθ+isinθ) 还可以进行下一步的变形。根据欧拉公式:
cosθ+ isinθ = eiθ
- 将复数以极坐标形式表示为:
- 现在复数的定义就与实部与虚部的两个分量 a、b 无关了,我们可以使用一个缩放因子 r 和旋转角度 θ 的形式来定义任意一个复数,而且能更直观地理解复数旋转与缩放的性质,即:
- 两个复数乘积的模 = 两个复数模的乘积
- 两个复数乘积的辐角 = 两个复数辐角的和
- 如果仅需要旋转,而不需要放缩,那么可以令 r=1 ,得到二维平面旋转公式(指数型):
四元数
- 由于三维空间比二维空间多了一维,为了实现类似的旋转,理所当然的想法就是在复数的基础上增加一个虚数j,则三维空间里的复数定义为p=a+bi+cj。
- 二维空间平面复数相乘以后会有
-1代替i2,而三维复数多项式相乘完以后,必然会出现交叉乘积:ij、ji,这些乘积的结果可不是-1。
- 因此虚数的个数应该与维度无关(
虚数个数=/维度-1),仔细想一下,在二维空间里复数的旋转轴是一维的,所以需要一个虚数i就可以,到了三维空间要想表示一个空间中的旋转轴就需要三维信息,所以除了i、j是不够的,还必须有k这个虚数(虚数个数=旋转轴维度),于是四元数就这样出现了,表达式为:
v代表i、j、k的多项式,对应于正常空间的三个维度,是虚数部;s代表实数部,对应于第四维:
p=s+xi+yj+zk
如何用i、j、k作为笛卡尔坐标系的单位向量:

四元数的乘积
- 两个四元数qaqb的乘积:
qaqb=[sa,a][sb,b]
=(sa+xai+yaj+zak)(sb+xbi+ybj+zbk)
=(sasb−xaxb−yayb−zazb)
+(saxb+sbxa+yazb−ybza)i
+(sayb+sbya+zaxb−zbxa)j
+(sazb+sbza+xayb−xbya)k
- 将后
3项和的多项式进行化简:前两列提取系数sa和sb作为公共部分,后两列直接写成ijk的虚数形式。并将加法展开再转换为[实数部,虚数部]的表达形式:
qaqb=[(sasb−xaxb−yayb−zazb),
sa(xbi+ybj+zbk)+sb(xai+yaj+zak)
+(yazb−ybza)i+(zaxb−zbxa)j+(xayb−xbya)k]
- 引入向量
a、b:
a=xai+yaj+zak
b=xbi+ybj+zbk
a、b的数量积(点积)的推导过程如下,i、j、k满足以下特点:
ii=jj=kk=1,ij=ik=jk=0
a ∙ b=(xai+yaj+zak) ∙ (xbi+ybj+zbk)
=xaxbii+xaybij+xazbik+yaxbji+yaybjj+yazbjk+zaxbki+zaybkj+zazbkk
=xaxb+yayb+zazb
a、b的向量积(叉积)的推导过程如下,i、j、k满足以下特点:
i=j×k;j=k×i;k=i×j
k×j=–i;i×k=–j;j×i=–k
i×i=j×j=k×k=i×j×k=0(0是指0向量)
a × b=(xai+yaj+zak) ×(xbi+ybj+zbk)
=xaxbii+xaybij+xazbik+yaxbji+yaybjj+yazbjk+zaxbki+zaybkj+zazbkk
=xaybk−xazbj−yaxbk+yazbi+zaxbj−zaybi
=(yazb−ybza)i+(zaxb−zbxa)j+(xayb−xbya)k
- 将
a、b的带入到qaqb的乘积结果中进行进一步化简,可得:
qaqb=[sasb−a⋅b,sab+sba+a×b]
- 这就是四元数乘积的一般式。由于实际中要旋转的向量在三维空间,所以将qa看做是第四维(实数部)为
0的纯四元数,则 qa=[0,a]或qa=(0+xai+yaj+zak),那么得到三维空间旋转公式:
qaqb=[−a⋅b,sba+a×b]
四元数与三维空间旋转
三维空间旋转数
- 参照二维平面的旋转数,定义三维空间的旋转(四元)数
q,使要旋转的向量旋转θ度,v是单位化的转轴方向:
q=[cosθ,vsinθ]
- 倘若
q 是单位四元数,满足 ∣q∣=1 ,可得:
∣q∣=cos2θ+(sinθ)2=1=1
- 因此,四元数 q 的逆 q−1 为其共轭:
q−1=qˉ
- 共轭四元数 qˉ 是:
qˉ=[cosθ,−vsinθ]
- 所以,对于单位四元数 q,其逆 q−1 是:
q−1=[cosθ,−vsinθ]
- 计算四元数
q和向量p的积,首先把p写成纯四元数的形式:
- 计算旋转后的向量 p′:
p′=qpp−1
- 引用三维空间旋转公式,旋转数q对应qb,待旋转向量p对应qa,应用上文提到的四元数乘积公式 qaqb=[−a⋅b,sba+a×b] 可得:
p′=qp=[0,p][cosθ,vsinθ]=[−p ⋅vsinθ, cosθp+p ×vsinθ]
- 考虑一个特殊情形:p与v正交(垂直)。这种情况下,v⋅p=0。所以上面的四元数就变成了纯四元数:
p′=qp=[0,cosθp+vsinθ×p]
- 值得注意的是,p′=qp和p′=pq的最终结果是不一样的。因为
ijk环是有顺序的,所以通过改变左右乘可以决定旋转方向是逆时针(p′=qp)还是顺时针(p′=pq)。
验证
- 验证上面公式的正确性,例如绕
z轴(k轴)旋转45度,那么:
q=[22,22k]
- 选一个特殊的
p,它和k轴正交,譬如把p放到i轴上,也就是:
p=[0,2i+0j+0k]
- 代入公式,由于
i和k正交,因此它们的点积为0:
p′=qp
=[22,22k][0,2i]
=[0,222i+222k×i]
=[0,2i+2j]
-
如果p′=pq,那么结果是[0,2i+2i×k]=[0,2i−2j],旋转的方向也就改变了。
-
[0,2i+2j]是一个绕了k轴转了45度的纯四元数,其向量部分的长度是:
p′=22+22=2
- 用图像展示旋转过程,红色向量绕蓝色向量旋转
45度得到黄色向量:

引入共轭四元数
待旋转向量不是纯四元数时需要引入共轭四元数
- 现在,考虑一个一般的四元数,即和
p不正交的四元数。此时v/=k,而是偏移45度:
v^=22i+22k
p=2i
q=[cosθ,sinθv^]
p=[0,p]
- 代入三维空间旋转公式:
p′=qp
=[cosθ,sinθv^][0,p]
[−sinθv^⋅p,cosθp+sinθv^×p]
- 用相应的值替换对应变量:
p′=[−22(22i+22k)⋅(2i),222i+22(22i+22k)×2i]
=[−1,2i+j]
- 此时,计算结果已经不是纯四元数了,并且没有旋转
45度、范数也不再是2(而是3)。用图像展示旋转过程:

严格来说,这样子在3维空间中表示p′是不正确的。因为它是一个4维的向量!为了简单起见,这里只将这个四元数的向量部分显示出来。
- 如何将它变为纯四元数呢?
Hamilton发现,如果对qp右乘q的逆,出来的结果是一个纯四元数,并且四元数向量部分的范数可以保持不变,验证一下:
q=[cosθ,sinθ(22i+22k)]
q−1=[cosθ,−sinθ(22i+22k)]
- 这里q−1=q∗是因为
q是单位四元数。再代入θ=45∘,得到:
q−1=[22,−22(22i+22k)]
21[2,−i−k]
- 现在,把前面算出来的
qp再次拿出来,进行四元数乘积运算:
qp=[−1,2i+j]
qpq−1=[−1,2i+j]21[2,−i−k]
=21[−2−(2i+j)⋅(−i−k),i+k+2(2i+j)−i+2j+k]
=21[−2+2,i+k+2i+2j−i+2j+k]
=[0,i+2j+k]
- 这下是纯四元数了,并且它的范数是:
∣qpq−1∣=12+22+12=4=2
- 这和原始的
p的范数一致。用图像展示旋转过程:

- 仔细观察上图,可以发现红色向量绕紫色向量旋转了
90度(而不是45度)到黄色向量,因此为了正确地让一个向量绕某个轴向量旋转某个角度,必须以目标角度的一半来计算:
q=[cos21θ,sin21θv^]
这就是旋转四元数的一般形式!
四元数插值LERP
SLERP可以在2个朝向之间平滑地插值。第一个朝向设为q1,第二个朝向设为q2(q1和q2是单位四元数)。被插值前的点设为p,插值后的点设为p′。而插值参数t,当t=0时会把p转到q1,当t=1时会转到q2。笛卡尔坐标系下(不是指四元数)的线性插值公式是:
qt=Lerp(q1,q21,t)=q1+(q2−q1)t
由于这样算出的qt不是单位四元数,所以需要对其进行归一化处理,也就是使用了归一化线性插值:
qt=Nlerp(q1,q2,t)=∣q1+(q2−q1)t∣q1+(q2−q1)t
这样虽然能保证qt是单位四元数了,但是并不能保证获得均匀的角速度,⻆速度首先会不断地增加,到t = 0.50之后会开始减速。
四元数插值SLERP
于是就有了球面线性插值Slerp方法,这种方法不对四元数q1和q2直接插值,而是对两者之间的夹角θ插值。
四元数的加减
qa=[sa,a]
qb=[sb,b]
qa+qb=[sa+sb,a+b]
qa−qb=[sa−sb,a−b]
- 对于四元数来说,减法等价于计算两个四元数的角度差:
Pdiff=q1−1q2(由q1Pdiff=q2推出)
将向量的球面插值用于四元数
- 球面线性插值的一般形式:
q′=q1(q1−1q2)t
- 球面线性插值的常用形式可以通过将向量的球面插值公式用于四元数得到。计算向量的球面插值的一般形式定义如下:
vt=sinθsin((1−t)θ)v1+sinθsin(tθ)v2
- 用图像表示如下:

- 这个公式可以原封不动地应用到四元数,从而得到四元数球面线性插值的常用形式:
qt=sinθsin((1−t)θ)q1+sinθsin(tθ)q2
- 但这个公式需要提供角度
θ,可以通过q1和q2的点积得出角度θ:θ=acos(q1⋅q2)
注意事项
- 当
q1和q2的角度差非常小,小到导致sinθ=0时,此时分母为零。这种情况下,可以使用归一化线性插值,此时归一化线性插值的误差非常小,基本不会与真正的Slerp有什么区别。
- 如果四元数点积的结果是负值(
q1和q2的夹角为钝角),那么后面的插值就会在4D球面上绕远路。为了解决这个问题,点积结果是负值时,将两个四元数的其中一个的系数和向量部分取反(并不会改变它代表的朝向),从而保证这个旋转走的是最短路径。
四元数插值SQUAD
slerp插值存在的问题
如果需要对多个四元数进行插值,对每一对四元数使用Slerp插值虽然能够保证每两个四元数之间的⻆速度是固定的,但是⻆速度会在切换插值的四元数时出现断点,或者说在切换点不可导。
举个例子,有q0、q1、q2三个四元数,分别对q0q1、q1q2 使用Slerp插值,当qt=q1时,⻆速度会突然改变。因此SQUAD插值以牺牲固定⻆速度为条件,从而在插值曲线连续的基础上,让一阶甚至是高阶导数是连续的(曲线连续我们称为C0连续, 达到一阶导数连续就叫做C1连续,在此基础上达到二阶导数连续叫做C2连续,以此类推)。
向量运用贝塞尔曲线
以向量序列的线性插值类比上面讲的内容:

- 这个曲线虽然是连续的,但是它的一阶导数(切线)在切换插值向量时都不是连续的。为了解决这个问题,最常使用的就是贝塞尔曲线。直接使用一个四次Bézier曲线(因为有五个点)来生成这个近似曲线。但是Bézier曲线只会经过初始点与最终点(插值),一般不会经过中间的控制点(近似),所以这样求出来的曲线虽然是可导的,但是插值曲线不会经过中间的三个向量:

- 为了解决这个问题,可以分段对每两个向量
vi和vi+1之间使用Bézier曲线进行插值,之后将所有的曲线连接起来。这就需要知道它们的前一个向量vi−1和后一个向量vi+2 ,通过这四个向量生成两个控制点si和si+1来控制曲线的趋势。此时,即可使用vi和vi+1作为端点,si和si+1作为中间控制点,使用一个三次Bézier曲线来近似这个两个向量之间的插值。如果想让最终的插值曲线达到C1连续,需要让前一个曲线在vi的控制点与当前曲线在vi的控制点分别处于最终曲线在vi处切线对等的两侧:

- 在上面的曲线中,蓝色的线就是曲线在点
vi处的切线,红色的点就是三次Bézier曲线的控制点,分别处于切线对等的两侧。对于两个端点v0和v4,直接将这两个向量的控制点取为它们本身(这不是唯一的做法),最终得到一个平滑的曲线。
四元数运用贝塞尔曲线
- 如果有四元数序列:
q1,q2,q3,⋯,qn−2,qn−1,qn
- 需要让曲线的一阶导数连续,还需要知道前一个四元数qi−1和后一个向量qi+2,如此一来就可以在qi和qi+1之间使用贝塞尔曲线进行插值:
qi−1,qi,qi+1,qi+2
- 使用上面四个四元数生成"辅助"四元数(si和si+1),它们是中间控制点:
si=exp(−4log(qi+1qi−1)+log(qi−1qi−1))qi
si+1=exp(−4log(qi+2qi+1−1)+log(qiqi+1−1))qi+1
- 在
t时刻的朝向就是:
squad(qi,qi+1,si,si+1,t)=slerp(slerp(qi,qi+1,t),slerp(si,si+1,t),2t(1−t))