Why do game programmers use quaternions to rotate a vector?

Started by
33 comments, last by dawidjoubert 18 years ago
OK.
1)Quaternions can represent rotations in a compact form.
2)Rotations are easy to combine.

I do not want to add a point “Gimbal Lock”.

But we should not forget that we need just 3 values to represent a rotation even when we are using matrix transformations but extracting this values from a matrix and creating the matrix from such 3 values is not so easy.

[attention] What I really like about matrix transformations is that they can do much more than just rotating an object, specially by using homogeneous coordinates we can translate objects and that is really interesting.
Advertisement
Quote:Original post by Kambiz
What I really like about matrix transformations is that they can do much more than just rotating an object, specially by using homogeneous coordinates we can translate objects and that is really interesting.

Which is often a very bad thing. Similarly, you could use strings to represent all the integers in your program, because they can do much more than just numbers. It is entirely possible to have too much expressivity.
For anybody working with quaternions, I recommend two books:

Quaternions and Rotation Sequences
Visualizing Quaternions

Let me clearly state I have read neither all the way through. I've read the half way through the first book. I've found it's mathematical analyses much more accessible than the second. There are some great proofs in there that have helped me more fully understand what's going on.

I've only read about a quarter of the second book. The math isn't nearly as clear and well-presented as the first title. OTOH, it's focused primarily on graphics whereas the first is primarily oriented towards aerospace and astrodynamics. It also has some very intriguing material in its introductory material that really makes me want to read it all the way through.

What do other people think?
Quote:Original post by haphazardlynamed
anyhow... I don't have anything against quaternions
I just get tired of people assuming that gimbal lock is exclusively a matrix issue and that switching to quaternions will magically fix everything
a search of the archives should reveal a few begginers' topics of "I switched to quaternions but still have gimbal lock! Help!" that will attest to the problems caused by this misconception...


I think you've misunderstood the point I was trying to make. My exact words, were: "My opinion is that most beginners use quaternions in order to avoid gimbal lock."
I only used this expression, to stress out that someone may blindly start using them -without understanding fundamental things about them- just because it is common belief that they "avoid gimbal lock".

Of course, gimbal lock is a problem inherent to the euler angles representation of rotations. Even if you used quaternions for each subsequent X/Y/Z rotation in euler angles, and concatenated them into a single quaternion, you'd still be experiencing the same problem. It doesn't mean that because you used quaternions inbetween, you would get rid of it!
And, in fact, no rotation is actually performed with a quaternion. In the end, you turn it into a matrix and apply it as world/model transformation.
Would this mean that it should be prone to "gimbal lock" just because it's not a quaternion anymore?
I think you misunderstood me; I'm sorry if it wasn't clear.

Quote:
Original post by Muse
Also, I don't think anyone mentioned the advantage quarternions have over a matrix representation in terms of maintaining the orthonormality of the transformation (that is, the transformation is less likely to become distorted or scaled due to rounding errors, since many fewer floating point operations are necessary for quaternion composition).

Indeed, this is a very important argument for the use of quaternions.
And in fact, the cost of re-orthogonalization is minimum compared to an orthogonal matrix.
Please correct me if I'm wrong, don't flame me to ashes.
I was under the impression that quaternions are generally more computationally expensive than matrices for the same use/applications and that matrices are themselves more expensive than equations for the same use/applications. I must admit this is probably a biased, personal but not necessarily untrue opinion. I've never used quaternions but I've been using rotation/translation/orbit/etc. equations for a long time now.

And I've never understood how using matrices for applying 3D rotations could somehow be less expensive than:
xi:=xo[ver]-rlx;yi:=yo[ver]-rly;xi:=zo[ver]-rlz;v1:=calf*xi+salf*zi;v2:=calf*zi-salf*xi;v3:=cbet*yi+sbet*v2; zr[ver]:=cbet*v2-sbet*yi+rlz;xr[ver]:=cgam*v1+sgam*v3+rlx;yr[ver]:=cgam*v3-sgam*v1+rly;

This is a very old little snippet of code I once used for offset camera rotation, around some arbitrary point in the world space. So it has 3 float adds and 3 float subs in addition to the rotation equations themselves.

And it's still probably much faster than using unbroken down matrices and applying matrix multiplication. But seeing as how today's GPUs do mostly all the work, nobody's getting too worked up about how horrendously wasteful matrix operations are... in both memory and processor time.

I presume it's even worse using quaternions to do smth. instead of just about anything else. If this is true, and a known fact, why do people use them so readily? I think it's because not all that many people INTUITIVELY understand the math behind some stuff. Instead of getting into the knitty gritty details of software optimisation through optimising its math, they just go the lazy man's way.

People would rather shave a little math research work off their development schedule than help their finished software save hundreds of millions of processor cycles needlessly wasted each runtime second. And what's worse, I'm pretty sure that whole established, fundamental 3D apis like OGL and D3D as well as their hardware implementation were and are developed the lazy (at maths) man's way also. There are tutorials written on how to do it the lazy man's way too!!!

I mean, just look at this "tutorial" on 3D rotation:

From the very beginning:
Quote:Okay, so I assume going into this tutorial that you know how to perform matrix multiplication.

If you're gonna do it using the CPU not GPU, I'd expect you'd at least try to NOT BLATANTLY WASTE processor time. And then goes on to say:

Quote:Sure, it's easy to make equations that will represent a rotation on any one of those axes, but just go ahead and try to make equations that will represent changes on three axes at once. If you manage to pull that off, make sure to let us know. Meanwhile, I'll present a way to do the rotations with matrices.

I rest my case.

[Edited by - sonyafterdark on April 1, 2006 4:31:44 PM]
Quote:Original post by sonyafterdark
Please correct me if I'm wrong, don't flame me to ashes.


Nothing intended as a flame here, but you are wrong about some things.

Quote:Original post by sonyafterdark
I was under the impression that quaternions are generally more computationally expensive than matrices for the same use/applications and that matrices are themselves more expensive than equations for the same use/applications. I must admit this is probably a biased, personal but not necessarily untrue opinion. I've never used quaternions but I've been using rotation/translation/orbit/etc. equations for a long time now.


Your first mistake is that you assume efficiency of transformation is the ultimate goal. There's also flexibility and total functionality. Straight linear equations will not be as flexible as matrices. Given modern SIMD architectures, it's possible that vector-matrix multiplication can be done in 4 instructions. That makes matrices more flexible and sufficiently efficient for my use.

Directly transforming a vector by a quaternion is more expensive than by a matrix. So if you're transforming more than a point or two, it's faster to convert a quaternion to matrix representation before transforming the vertices.

OTOH, compositing quaternion rotations is faster than matrix transforms. If your transforms have translations in there, the advantage is lost.

How do you propose, under your system to do a hierarchical transformation? I'm guessing you avoid that. Let's start with a simple example. You have a tank. How do you set up the transform for both the tank body and the turret? How about setting up the transform for the moon orbiting around the Earth that orbits around the sun which rotates around with our galaxy?

Quote:Original post by sonyafterdark
This is a very old little snippet of code I once used for offset camera rotation, around some arbitrary point in the world space. So it has 3 float adds and 3 float subs in addition to the rotation equations themselves.

And it's still probably much faster than using unbroken down matrices and applying matrix multiplication. But seeing as how today's GPUs do mostly all the work, nobody's getting too worked up about how horrendosly wasteful matrix operations are... in both memory and processor time.


Yes, your snippet of code is faster than matrices; however, it's not nearly as general. How fast are your transformations if you have a spatial hierarchy? Matrices are O(1). You'll end up with an O(n) system, the order based off the depth of the hierarchy. Your system of dealing with transforms can get very complex. Say you need to transform from one coordinate space to another. Given the second example above, please show me the code to transform from one satellite's local space to a Mars-local coordinate space. Yeah, it's a little contrived, but there are similar conversions that happen in games all the time.

As far as horrendously wasteful goes, how much memory do you think you'll burn on matrices compared to model vertices, textures, the program itself, etc.?

Quote:Original post by sonyafterdark
I presume it's even worse using quaternions to do smth. instead of just about anything else. If this is true, and a known fact, why do people use them so readily? I think it's because not all that many people INTUITIVELY understand the math behind some stuff. Instead of getting into the knitty gritty details of software optimisation through optimising it's math, they just go the lazy man's way.


They're effective at interpolating orientations. How do you propose interpolating between any two rotations in your transformation system? As far as intuition goes, I suspect that you avoid quaternions precisely because you haven't put the time in to intuitively understand them. You are the lazy man. I don't mean this as a flame although I understand how it might be hard to take it any other way. How much rotation interpolation have you done? Have you ever tried to interpolate human animation data? If you're not interpolating rotations then quaternions might be best avoided. Please note that says "might".

Quote:Original post by sonyafterdark
People would rather shave a little math research work off their development schedule than help their finished software save hundreds of millions of processor cycles needlessly wasted each runtime second. And what's worse, I'm pretty sure that whole established, fundamental 3D apis like OGL and D3D as well as their hardware implementation were and are developed the lazy (at maths) man's way also. There are tutorials written on how to do it the lazy man's way too!!!


How do you propose 3D hardware handle transformations if not through a matrix? It's possible, but I suspect any answer you give will be far inferior to the current matrix-based pipeline.

Quote:Original post by sonyafterdark
I rest my case.


Too bad your client will be convicted and sent to the chair.
Quote:Original post by Troll
[...]I recommend[...] Quaternions and Rotation Sequences


Seconded. This book is very well-written, and has some very insightful material which I haven't found elsewhere presented in such an accessible manner. I feel anybody who is sufficiently interested in quaternions should give at least the first half of this book a chance.
For all the noobs out there:

Rotation with 3x3 matrix
x_rotated=m[0][0]*x+m[1][0]*y+m[2][0]*z;y_rotated=m[0][1]*x+m[1][1]*y+m[2][1]*z;z_rotated=m[0][2]*x+m[1][2]*y+m[2][2]*z;

9 multiplications, 6 additions.
If you want to add in translation there it'll need 9 additions.
sonyafterdark's thing does 12 multiplications [lol], as much as 4x4 matrix multplication, but without all the generality. Even more, note that with matrix these multiplications can all be done in parallel, so it will be faster.

4x4 matrices is used in rendering because usually you not only need to rotate and scale and whatever but also need to do perspective transformation for rendering. That is, for every point, to find screen position and zbuffer value, you just do single 4x4 matrix multiplication and then single division.
The whole point of matrices (AND quaternions) is that you can combine as many operations as you wish into single matrix or single quaternion, and then use it.
For example, you have camera, and you have spaceship. You combine these matrices so internally to transform to camera's view only one matrix multiplication is done. Same for turret of tank, etc.

Remember, in 3D rendering, you do few transformations and transform MANY points. It is much more important to transform points faster, and matrices let you put as many consequent transformations as you wish into single matrix.
With all the "methods" presented there, what you will do if you need to do several transformations in sequence? apply your formula twice? Many times? THAT will be wasteful. 3D models has many points; with one point your methods may take comparable time, but several points (>3) you see the adwantage of using matrices - you prepare transformation before looping through all points, then for many points you need to do only *one* transformation per point that does LOT of stuff (typically, several translations, several rotations, and perspective trasnsform, all by one linear transformation (and one perspective divide)).

As for quaternions, quaternions is used because them is good for combining rotations, interpolating rotations, accamulating rotations (as in spaceship game where you fly around), etc. If you don't do that, you don't need quaternions.
It is very rare to transform vectors by quaternion directly. For rendering, quaternions is converted to matrix. Quaternions is very rarely used to directly rotate a vector; but even in this case it is simpler and faster than formula 4 (trigs are slow).

Really, before attacking quaternions, you need to first understand what them are.
Quaternion stores axis and sine and cosine of half angle. It is equivalent to axis angle, with one significant difference: quaternion operations is much faster because them do not use trigs (sine and cosine is precomputed; sine and cosine of resulting transformations is obtained with few additions and multiplications rather than sin and asin).

Just for example, try conbining two axis-angle rotations into one axis-angle rotation. Try making spaceship that can turn in any direction (with axis-angle or with euler angles). It will be significantly more complicated AND wasteful than with quaternions.

As for formula 4, i how it is simpler or faster than
X' = Q * X * ~Q
??? [grin]

Also, formula 4 does trigs. And trigs is slow. Okay, you can do trig once and cache cosine and sine somewhere so you wonj't do trigs per point. Then you can do more precomputations. But whoops, as soon as you start to optimize axis-angle you get quaternion.[lol]

[Edited by - Dmytry on April 2, 2006 4:50:18 AM]
So what? the code was for explanatory purposes. perhaps I should've written a clearer example.
oldcam_cen_x:=newcam_cen_x;oldcam_cen_y:=newcam_cen_y;oldcam_cen_z:=newcam_cen_z;new_alfa:={..};{I now it's spelled wrong, but the code looks better}new_beta:={..};{I now it's spelled wrong, but the code looks better}new_gama:={..};{I now it's spelled wrong, but the code looks better}newcam_cen_x:={..};newcam_cen_y:={..};newcam_cen_z:={..};rlx:=newcam_cen_x-oldcam_cen_x;rly:=newcam_cen_y-oldcam_cen_y;rlz:=newcam_cen_z-oldcam_cen_z;calf:=cos(new_alfa);salf:=sin(new_alfa);cbet:=cos(new_beta);sbet:=sin(new_beta);cgam:=cos(new_gama);sgam:=sin(new_gama);for ver:=1 to ver do begin {ver is the number of vertexes in the scene, BTW}    xi:=xo[ver]-rlx;{1 sub}    yi:=yo[ver]-rly;{1 sub}    xi:=zo[ver]-rlz;{1 sub}    v1:=calf*xi+salf*zi;{2 muls and 1 add}    v2:=calf*zi-salf*xi;{2 muls and 1 sub}    v3:=cbet*yi+sbet*v2;{2 muls and 1 add}    zr[ver]:=cbet*v2-sbet*yi+rlz;{2 muls, 1 add and 1 sub}    xr[ver]:=cgam*v1+sgam*v3+rlx;{2 muls, 2 adds         }    yr[ver]:=cgam*v3-sgam*v1+rly;{2 muls, 1 add and 1 sub}end;{this is for camera rotation, ok?}{a total of 6 subs, 6 adds and 12 multiplications per rotation per vertex per frame}

if it were just simple, dumb rotation around the origin of the world space it would be a total of only 3 subs, 3 adds and 12 multiplications per rotation per vertex per frame. alternately you can just use that each frame that you know you'll rotate around the origin of world space itself.

But look at the bang you get for the buck: smart rotation about an arbitrary point in world space. Like in "matrix reloaded" when the camera rotates around Neo looking at him? except you can rotate about any arbitrary point, not just one you're looking at. I'm sorry that you think it has anything to do with actual camera translation.

There's another, entirely separate, set (actually 2, 1 for relating world space to camera space translation and viceversa) of equations for that also, and again it's far cheaper that way than using matrices to translate.

Those equations are derived from the rotation equations and the counter-rotation equations. Kinda like the translation matrices are derived from the rotation matrix and the inverse of the rotation matrix. Of course, using the equations is cheaper, faster and more accurate.

You can relate object/camera translation in CAMERA SPACE TO WORLD SPACE AND VICEVERSA keeping the 2 spaces in sync with one another using those equations without applying a single rotation but, Of course, after lots and lots of translating over thousands of years, without any refreshing of the camera space through a rotation of the world space, you're going to get noticeable desynchronization of the 2 spaces. Which usage of matrices would only help you reach that much sooner. The first rotation performed will teleport the camera.

Even using SIMD instruction sets you're still doing more multiplications than needed, albeit faster, again by taking advantage of hardware support of such technology. That the program runs on a machine with a processor with SSE3 support, for example, does not "take away" from the ineffieciency of the code.

And I should think efficient (and implicitely fast) code is quite important in general and especially in game programming.

I think my snippet of code can be easily adapted to usage of SIMD instruction sets quite easily. Or am I wrong? And then it would again be a lot faster than your matrix operations, even using SIMD, the speed of which you are quite satisfied with anyhow. What I find unbelievable is how someone can even begin to compare the expense of matrix multiplication (even using SIMD) to simple float multiplication to somehow explain how using matrices is actually faster. It boggles the mind.

Also about linear equations being cumbersome or such to implement. Nobody's halting anyone from writing SDK units (or classes) that export procedures and functions based on BETTER MATH AND ALGORITHMS for high level programmers to make use of.

Just because high level programmers find thinking in matrices easier doesn't make using them better or faster. In fact, I think OGL and D3D are the result of too much say given to high level programmers and too little to mathematicians and engineers involved in the projects. But who's gonna write that proper software? People who can't eat cereals without using a matrix?

As I said, I've never used quaternions. I've never wanted or needed to smoothly interpolate between rotation angles or simulate human movements, etc. That is just way out of my hobbyist programmer league. Thus I avoided the subject. You dragged me in it. And even if I would need to do something like this, what need would I have for quaternions to simply interpolate between 2 angles?

Actually nearly all the math I use in my programs I develop on my own only to document myself later (if at all) upon what it might be that I used or how others attempted to solve the problem before me. I seek established solutions to problems I managed to solve merely to compare with my own solutions. And I've never had/wanted to solve anything that might need something like a quaternion for a solution. And don't think I will anytime soon.

Hierarchical transformation? What is it? Rocket science or smth.? I've never tried to implement something like this. But I don't see how the WAY you do a rotation can have any bearing on having to do that particular rotation or not.

Just off the top of my head right now:

Let's say you have a shoulder joint and an elbow joint. You rotate the arm around the shoulder joint from world space overwriting to camera space. Along with the arm you rotate the elbow joint around the shoulder joint from world space overwriting to camera space just like you did with the vertexes of the arm.

You take the rotated elbow joint position and substract the normal, unrotated, elbow joint position that you still have in world space. You apply this vector to every (and only) vertex of the forearm from world space and overwrite to camera space to shift it where the elbow joint now is while refreshing the mesh in camera space at the same time.

Now you add the euler angles by which you rotated the arm and elbow joint around the shoulder joint to the euler angles by which the forearm was already rotated around the elbow joint or by which you want to rotate it.

Then you rotate the forearm from camera space around the elbow joint (from camera space) by these summed angles and overwrite, yes, to camera space. If you also had a wrist joint and fingers to deal with you'd only rotate the wrist joint position along with the forearm vertexes and leave the fingers alone for now.

Now you'd do for the fingers' vertexes what you did for the forearm's. Apply the vector that is the difference between the wrist joint position in camera space and the wrist joint position in world space to all the vertexes of the fingers from world space overwriting to camera space to shift them appropriately.

Then you rotate the fingers from camera space, overwriting to camera space, around the wrist joint camera space position by euler angles that are the sum of angles of rotation around the shoulder, elbow and wrist joints. And so on and so forth.

Finally you apply camera rotation to all the membres and their kid joints from the first membre that was rotated this frame (in the linked tree's order of enumeration from the root) down to the "fingers" (that have no kid joints) to the current camera alfa, beta and gama euler orientation angles reading from camera space and overwriting to camera space. But be careful that you only apply this rotation to the vertexes and joint positions that were transformed from world space not to any others.

And you're finally done. Of course, if it's the camera that rotates from this particular frame to the next, you're gonna have to go through ALL the membres and their respective joints' transformations from the root all the way down to the fingers all over again, regardless whether any of them have actually transformed or not, and finally apply camera rotation from camera space overwriting to camera space to the entire transformed structure as well as other stuff that you rotate from world space directly, without any additional transformation unless, of course, they're hierarchical structures as well.

Simple it is not. Nor very clear, I'm sure. Yet it is the only way possible to do this without additional costs in either memory for using intermediate vertex buffers for various stages of transformation or contending with worse mesh degeneration in either camera space or, more tragically, world space depending on the approach.

If you think there is and that somehow performing rotations with matrices is going to get you there while performing them with equations isn't, you're just plain wrong.

I don't see how using matrices TO CALCULATE ROTATED COORDINATES is any different from using equation systems to CALCULATE ROTATED COORDINATES except in worse performance. Floating point precision is finite, no matter what. The input is the same, the output is theoretically the same using either matrices or equations. What happens in the middle affects nothing but speed, memory usage and, perhaps, precision of result. And precision wise, equations systems will beat matrices everytime.

For the same reason they're faster and use less memory. Fewer operations performed on input data.

Either you're talking about matrix operations like they're the Holy Grail that would somehow nullify the physical finite precision limitation of floating point format, or I'm missing something. Did you assume I don't know about world space and camera/object space? Or about finite floating point precision?

Perhaps you should review the basic 3D math you think you know before lecturing others about the obvious advantages of using quaternions and matrix operations and seeking to implement redundancies in a program's code as much as possible.
sonyafterdark:
Really, it'd be good if before proposing some kind of "faster" schemes people would learn at least something about topic.

As for rotation around arbitrary point:
simple but stupid way:
construct 3x3 matrix m from euler angles, or whatever other input data you like, such as quaternion, axis-angle, etc.for n:=1 to num_vertices do begin  v_rotated=point+m*(v-point);// one vector subtract, one vector addition, and one matrix*vector multiplication.// total 3+6=9 additions, 3 subtractions, and 9 multiplicationsend;


smarter way, using m*(a-b)=m*a-m*b identity (we can get subtracts out of loop).

construct 3x3 matrix m from euler angles, or whatever other input data you like, such as quaternion, axis-angle, etc. translation:=point-m*point;for n:=1 to num_vertices do begin  v_rotated=translation+m*v;// one vector addition, and one matrix*vector multiplication.// total 3+6=9 additions, and 9 multiplicationsend;

edit: also, these two pieces of code shows WHY matrices is faster in any practical case. You coulda do similar optimization in your code to move subtracts out of loop, of course. But your code is so cumbersome that this is beyond your abilities. Whereas with matrices every newbie can do that kind of optimizations.

sidenote: Practically, 3D engines use 4x4 matrix (rather than 3x3 matrix and translation) as it lets combine all your rotations, translations, and most of perspective transformation, and even transformation to pixel coordinates into single matrix. This way as much as possible is moved out of the loop. It is much more efficient to multiply every point by 4x4 matrix than to rotate every point, translate it, then project it, then compute pixel coordinates.

In summary, matrices (and quaternions too[lol]) is a: more efficient than what you are doing, b: more flexible, c: simpler to work with.


edit:
As for your arm example, sorry, will not work correctly. Better try actually implementing it with your method(and make it actually work), this way you will learn lot of useful and interesting things and also see why people use matrices. note: if you just add euler angles of two joints you generally don't get rotations combined like it happens in real world.

Representation matters there; some representations can be concatenated efficiently (matrices, quaternions), and some can not (euler angles, axis-angle)

[Edited by - Dmytry on April 2, 2006 1:13:44 PM]

This topic is closed to new replies.

Advertisement