笔记来自《游戏引擎架构》Jason Gregory著 第二版,4.4四元数,Page144。
引入:矩阵变换的三个问题
3*3矩阵可以表示三位中的任何旋转,但是他又三个问题。
1.9个浮点型表述只有三个自由度的旋转显得多余。
2.矩阵乘法过于复杂对于计算机来说,我们需要运算更快的旋转方法。
3.不能平滑插值。
如此,我们有quaternion q = {x,y,z,w}
四元数由威廉哈密顿爵士发明,作为复数的衍生,其定义x,y,z为虚部,w为实部,即x^2 = y^2 = z^2 =-1,w^2 = 1。
我们并不需要使用虚数,四元数并不是为旋转而生,我们只需要知道,单位长度四元数可以表示旋转,
即x^2 + y^2 + z^2 + w^2 = 1。
需要注意:四元数同矩阵一样代表一种变换而不是一个具体到位置的旋转,四元数的作用对象是向量而不是一个点,你可以让一个箭头绕轴旋转90度,但是你不能让一个点旋转,因为点是没有方向的。这可能影响你理解四元素。
旋转的三维表现
矢量vector 标量scalar。
以下标粗字母为矢量。
q = [qv,qs],qv矢量部分是一个Vector3,qs标量部分为float。
q = [a*sinθ/2 , cosθ/2],在三维中,a为旋转轴的单位向量,绕轴a按右手法则旋转θ,即为该q定义的旋转。
旋转的乘法
注意:两个四元数相加不表示任何旋转,因为其模长不等于1。
p和q表示两个旋转,两者合成旋转用乘法表示pq,四元数的乘法有多种,此处用拉各斯曼积Grassmann product草人积
pq = [psqv + qspv + pv + qv ,psqs - Dot(pv,qv)], Dot是点乘。
共轭四元数和逆四元数
四元数[0,0,0,1]表示零旋转(sin0 = 0,cos0 = 1,很合理)。
逆四元数和原四元数相乘 = [0,0,0,1];
计算逆四元数首先需定义共轭四元数conjugate的量 q* = [-qv,qs],共轭:矢量相反标量相同。
因为逆矩阵 q逆 = q*/|q|^2,逆四元数等于共轭四元数除以模长的平方。因为单位四元数模长=1,故q逆 = q*= [-qv,qs]。
因此可见求逆四元数速度远远快过求逆矩阵。
还有两个公式记住: (pq)* = q*p*,(pq)逆 = q逆p逆。注意顺序。
用四元数旋转一个矢量
我使用四元数q去旋转矢量v,得到矢量v′
首先把矢量v = [x,y,z]转变成四元数v = [x,y,z,0]
v′ = roatate(q,v) = qvq逆 = qvq*
另一种运算方法不用将v转换成四元数,运算量更加少
v′ = roatate(q,v) = v + 2qv ×(qv × v + qsv)
四元数的串接
如矩阵一样四元数也可以串联,如果将一个物向量v先进行旋转q1,然后q2,最后q3,我也可以得到旋转q合,旋转一次即可得到旋转三次同样的结果。
q合 = q3q2q1,注意顺序
v′ = q3q2q1vq1逆q2逆q3逆 = q合vq合逆
3*3矩阵和四元数是可以相互转换的,转换比较复杂自行百度
四元数的线性插值Lerp和球形插值Slerp,这是应用四元数的主要原因。
线性插值LERP
q插 = LERP(qa,qb,β) = ((1-β)qa + βqb)/|(1-β)qa + βqb|四元数除以自己模长即归一化
球面插值SLERP
由x^2+y^2+z^2+w^2 = 1可知,四元数实际上是四维空间超球(HyperSphere)上的点。
线性插值实为大圆(great circle,超球的切面)的弦上的插值,而球面插值是大圆的弧上的插值。
他们的区别在于,当β匀速变化的时候Slerp结果也是匀速变化,但是Lerp并不匀速,他在β接近0,1时较慢,在0.5左右变化较快。
SLERP与LERP类似,但是权值不同
SLERP(p,q,β) = w*p + m*q; 其中权值w = sin(1-β)θ/sinθ; 权值m = sinβθ/sinθ;
θ为两个四元数的夹角,很容易通过四维向量点积求得 cosθ = qxpx+qypy+qzpz+qwpw,然后arccos该值求得θ。
需要注意SLERP比LERP昂贵许多,而LERP表现并不差。
来源:oschina
链接:https://my.oschina.net/u/4368807/blog/4497437