Practical issues with quaternions

Started by
18 comments, last by HAM 16 years, 5 months ago
I'm having some trouble understanding how to use quaternions in a practical way in my engine. I tried something where I stored the game state by a pitch and azimut angle, but before I managed to implement this with quaternions, I found out that many professional engines seem to use a quaternion (and a position vector) to store the STATE of each object, something that seems confusing to me. The way I understood it, a system storing the state in the form of a quaternion works like this: i. On mouse rotation: 1. get user rotation angles a_p and a_a (pitch and azimut, respectively) 1. Let q be the old quaternion representing the orientation of the object 2. Let x be the x axis in world space (i.e. 1,0,0). 3. Let x' := q * x * q.conjugate() 4. Make a quaternion out of x' and a_p, maybe normalize etc 5. Let q' := x' * q' * x'.conjugate() 6. Let y be the y axis in world space (i.e. 0,1,0). 7. Let y' := q' * y * q'.conjugate() 8. Make a quaternion out of y' and a_a, maybe normalize etc 9. Let q'' := y' * q' * y'.conjugate() 10. update object state with q set to q'' ii. When rendering this object: 1. calculate a rotation matrix R from q by using one of the quaternion-to-rotation-matrix translation recipes given in almost all quaternion tutorials on the web, and then use W = T * R as model-to-world matrix in the rendering My questions are: - Is this the correct maths/pseudo code? - Is this really that much faster than using matrices (especially if you compare quaternions to SIMD optimized matrix-vector multiplications? Or are there some optimization shortcuts that I've forgotten in the listing above? - Finally, how should I constrain the pitch angle to a certain allowed interval?
Advertisement
Quote:Original post by all_names_taken
I'm having some trouble understanding how to use quaternions in a practical way in my engine. I tried something where I stored the game state by a pitch and azimut angle, but before I managed to implement this with quaternions, I found out that many professional engines seem to use a quaternion (and a position vector) to store the STATE of each object, something that seems confusing to me.

The way I understood it, a system storing the state in the form of a quaternion works like this:

i. On mouse rotation:
1. get user rotation angles a_p and a_a (pitch and azimut, respectively)
1. Let q be the old quaternion representing the orientation of the object
2. Let x be the x axis in world space (i.e. 1,0,0).
3. Let x' := q * x * q.conjugate()
4. Make a quaternion out of x' and a_p, maybe normalize etc
5. Let q' := x' * q' * x'.conjugate()
6. Let y be the y axis in world space (i.e. 0,1,0).
7. Let y' := q' * y * q'.conjugate()
8. Make a quaternion out of y' and a_a, maybe normalize etc
9. Let q'' := y' * q' * y'.conjugate()
10. update object state with q set to q''

ii. When rendering this object:
1. calculate a rotation matrix R from q by using one of the quaternion-to-rotation-matrix translation recipes given in almost all quaternion tutorials on the web, and then use W = T * R as model-to-world matrix in the rendering

My questions are:
- Is this the correct maths/pseudo code?
- Is this really that much faster than using matrices (especially if you compare quaternions to SIMD optimized matrix-vector multiplications? Or are there some optimization shortcuts that I've forgotten in the listing above?
- Finally, how should I constrain the pitch angle to a certain allowed interval?
As far as I can determine, the use of quaternions (and of incremental rotations) as described above is more or less pointless. Also, I would think that any minor differences in speed in relation to the matrix version would be a) negligible and b) unimportant (assuming that this is only being done once per game update).

If you want FPS-style motion (which is what your post suggests), I recommend simply representing your object in terms of a position and an Euler-angle pair (azimuth-elevation, pitch-yaw, or whatever). Then, simply construct a matrix from these data when needed. (Incidentally, this makes pitch/elevation constraint trivial.)

I have some links I can post if you need more info on how to implement this.

(BTW, even when using Euler angles/spherical coordinates, you can easily construct a quaternion-vector pair if needed, say, for use with an existing scene graph system or third-party API.)
Ok... but why are quaternions so popular and used in so many engines (for example Ogre3D), if they are so problematic? What is all the hype about?
Some adventages over matrix

- It takes 4 floats values to store rotations.

- some people say it help to avoid the gimback lock effect in some cases.

- Quaternions are very good for doing smooth interpolation, that mean calculationg all orientation you want between a initial and final orientation; that is done using an algorith called SLERP, for example if you do NewRotation=SLERP(initial,final,k); "k" is a value between 0 and 1 so if you do a loop like 0.01 to 0.99 you will get a smooth rotation going from "initial" to "final" quaternion; that is a must when doing character animation where you need to calc frames between keyframes.

Using quaterion for camera movement is also good if you want to do some kind inertia & acceleration using the initial camera orientation and the desired final camera orientation.

Quote:Original post by tpascal
Some adventages over matrix
- some people say it help to avoid the gimback lock effect in some cases.
These people are ignorant and wrong.
Quote:- Quaternions are very good for doing smooth interpolation

That's the biggie. Even linearly interpolating quaternions looks surprisingly good. Also, quaternions are more numerically stable than matrices; it takes them longer to skew significantly from SO(3), and renormalizing them in a reasonable way is much simpler.
Quote:Using quaterion for camera movement is also good if you want to do some kind inertia & acceleration using the initial camera orientation and the desired final camera orientation.
Another good reason. Everyone talks about SLERPing, but SQUADing (spherical quadric interpolation) can produce some really great results, particularly for camera motion. Others have used NURBS curves over quaternions-as-vectors to accomplish similar effects.
I've also heard that quaternions avoid gimbal lock and I am surprised to learn that it's not true. Does anyone know how or why that rumor started?
Quote:Original post by CDProp
I've also heard that quaternions avoid gimbal lock and I am surprised to learn that it's not true. Does anyone know how or why that rumor started?

As far as I can tell, it started because everybody "knows" that gimbal lock is bad, yet practically no one understands what it is. And since quaternions differ from euler angles in not exhibiting gimbal lock, people somehow associated gimbal lock with "normal" rotation, and lack of gimbal lock with "quaternion" rotation.

In reality, gimbal lock is an effect which one rarely encounters in game development; unless you are writing a flight simulator or an IK solver, you're unlikely to ever see it.
Gimbal lock is a result of improper combinations of successive rotations: when the rotation axis of a later rotation is placed to be in parallel with the rotation axis of a previous rotation. Since Euler angles are a rotation representation that is defined to be the combination of three rotations, running into situations with gimbal lock seems to be easier, but that's due to a lack of understanding of how to properly combine rotations represented by Euler angles.
Ok, thanks for clearing up the gimbal lock issue, now my use of matrices feels much better :)

And if I understood correctly, in practise I should mainly be using quaternions for cutscenes and the like?

About character animation, is the effect much worse with matrices? I was planning to use a matrix palette for bones animation, but does that look bad? Should I instead try to create a quaternion+position pairs palette for bone animation in my engine?
Quote:Original post by all_names_taken
And if I understood correctly, in practise I should mainly be using quaternions for cutscenes and the like?
Erm, no - what gave you that impression exactly? :)

Just think of it this way: you can use a quaternion anywhere you would normally use a rotation matrix (more or less), and the only differences are going to be internal (i.e. not visible) trade-offs in storage requirements, efficiency, code clarity, and so on.
Quote:About character animation, is the effect much worse with matrices? I was planning to use a matrix palette for bones animation, but does that look bad? Should I instead try to create a quaternion+position pairs palette for bone animation in my engine?
Again, it's not about 'effect' or how something looks - the person viewing the simulation is not going to be able to determine whether matrices or quaternions were used just by looking.

IMO there's little point in choosing a rotation representation until you have a pretty good understanding of the differences between them. For this purpose I recommend this article, which provides an excellent overview of the subject.

This topic is closed to new replies.

Advertisement