Unity中四元数quaternion的学习笔记

笔记来自《游戏引擎架构》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表现并不差。

猜你喜欢

转载自blog.csdn.net/GameObject14715/article/details/108005613
今日推荐