使用四元数旋转向量 Rotating vectors using quaternions

整理使用四元数旋转向量的直接公式和对应实现。

使用四元数旋转向量 Rotating vectors using quaternions

要用四元数旋转向量,我们首先用该向量构造一个四元数,方法是将它 (标准化后) 放入四元数的向量部分,并保持标量部分为零,这会是一个 纯四元数 Pure Quaternions

v=(vx,vy,vz)v=(vx,vy,vz,0)\begin{align*} \vec{v} &= (v_x,v_y,v_z) \\ v' &= (v_x,v_y,v_z,0) \end{align*}

接下来,左乘所需的四元数,然后右乘其逆 (单位 四元数 的逆等于 共轭),这是我们之前推导出的结果

r=qvq1=qvq\begin{align*} r &= q \cdot v' \cdot q^{-1} \\ &= q \cdot v' \cdot q^\ast \end{align*}

旋转以后的向量存储在结果四元数 rr 的向量部分,并且该四元数的标量部分应该为零

虽然两次 四元数乘法 已经足够简洁,但是我们可以利用旋转后的结果四元数 标量部分为零 这个事实来简化我们的计算,进一步加快计算效率,设

q=(qv, qs),vq = (\vec{q}_v, \ q_s), \quad \vec{v}
  • 其中,qv=(qx,qy,qz)\vec{q}_v = (q_x,q_y,q_z) 是四元数 向量部分qs=qwq_s = q_w标量部分
  • v\vec{v} 是被旋转的 原向量

r=qvqr = q \cdot v' \cdot q^\ast向量-标量记号 全展开,会得到一个包含很多 qvv,  qv×v,  qs\vec{q}_v \cdot \vec{v}, \ \ \vec{q}_v \times \vec{v}, \ \ q_s 的混合项,经历过手动展开、消掉实部、再合并类似项的过程,整理完后可化成:

v=2(qvv)qv+(qs2qvqv)v+2qs(qv×v)=v+2qs(q×v)+2(qv×(qv×v))\begin{align*} \vec{v}' &= 2(\vec{q}_v\cdot \vec{v})\vec{q}_v + (q_s^2 - \vec{q}_v\cdot \vec{q}_v)\vec{v} + 2q_s(\vec{q}_v\times \vec{v}) \\ &= \vec{v} + 2q_s(\vec{q}\times\vec{v}) + 2(\vec{q}_v\times(\vec{q}_v\times\vec{v})) \end{align*}
  • 两种写法完全等价

这就是 “少量点乘 + 少量叉乘 + 若干乘标量” 的常见高效公式

Vector3 Mul(Vector3 v, Quaternion q) {
    Vector3 u = {q.x, q.y, q.z};   // q_v
    float  s = q.w;                // q_s
 
    return 2.0f * Dot(u, v) * u            // 2(q_v·v)q_v
         + (s * s - Dot(u, u)) * v         // (q_s^2 - |q_v|^2)v
         + 2.0f * s * cross(u, v);         // 2q_s(q_v × v)
}

只用了 1 次叉乘、2 次点乘、若干标量运算,比“先算 qvq v'、再乘 q1q^{-1}”节省大量乘加,并且 直接得到旋转后的向量