Today’s post is only a small gem I accidentally came across while I was looking for something entirely different: a faster method of multiplying a quaternion by a vector.
I use quaternion-vector multiplication (rotating a vector by a quaternion) mostly in two places:
- When building the global pose of a skeleton from its local pose, as discussed in this blog post.
- In vertex shaders that are used with instanced rendering, so I only have to send one quaternion (float4) instead of a whole rotation matrix (float3x3).
The canonical way of multiplying a quaternion q by a vector v is given by the following formula:
v' = q * v * conjugate(q)
where the vector v is being treated as a quaternion with w=0, so the above essentially boils down to two quaternion multiplications, which are a bit expensive.
Turns out there is a faster way, which is the following:
t = 2 * cross(q.xyz, v) v' = v + q.w * t + cross(q.xyz, t)
The faster method comes courtesy of Fabian Giesen (ryg of Farbrausch fame), who posted this to the MollyRocket forums years ago. Another derivation, yielding the same result, can be found here.
In my SSE2 code path, the new method is about 35% faster than the original. Enjoy, and don’t forget to share this gem with other people!
Pingback: Understanding quaternions | Light is beautiful
I optimized the quaternion rotation formula for a vector P and came up with this formula. Where v is the vector part of the quaternion and w is the scalar part. It runs about 15% faster than the formula that you posted here.
p’ = (v*v.dot(p) + v.cross(p)*(w))*2 + p*(w*w – v.dot(v))
It is weird, that your method, which contains 22 float multiplications, 15% faster than post-proposed method with 15 float multiplication, If anything – it should yours to slower.
I don’t think that’s right, Francisco. You’ve turned the term v.cross(v.cross(p)) into -v.dot(v)*p, which is only true in the special case v and p are perpendicular.
Sorry, I somehow missed an entire term of the equation. I have now double-checked that Francisco’s formula is correct.
Francisco, I believe there’s a two missing —
. . . + p*(2*w*w – v.dot(v))
I believe Francisco’s alternate solution is correct otherwise, with the only assumption being that the quaternion is normalized (which is a common requirement when using them for rotations).
FYI both source links you provide for the derivation are dead. I think the forum post you mention is archived here: http://mollyrocket.com/forums/molly_forum_833.html albeit in a format that is rather difficult to read.
This is also what the glm library uses. I found the implementation changes between versions, so the latest one should reflect what the developer finds the fastest.
Pingback: Shader graph: Rigid body animation using vertex animation textures – Vadim on Writing
Pingback: Day 2 – Fixing the camera | Game Dev | Blog
Pingback: Faster quaternion product rotations