Skip to main content
GameDev.net gamedev.net
🔒 Locked

quaternions as orientation

Started by cold_storm Jan 1, 2006 at 7:27 PM 60 replies 7.4k views
Original Post
cold_storm
cold_storm
Anybody know how to use quaternions to orient a mesh in OpenGL?? It does not make sense to me how 3 imaginary numbers and a real number can represent the orientation of a mesh.
Sneftel
Sneftel
First of all, they aren't three imaginary numbers and a real number. They're four real numbers which are used as a single four-dimensional complex number, just as two real numbers can be used as a single two-dimensional complex number.

Secondly, OpenGL does not use quaternions directly. To use quaternions with OpenGL, you generally convert them into rotation matrices.

Thirdly, if you're interested in knowing exactly how quaternions work, rather than just how you can use them, read this.
someusername
someusername
What you suggest, (using quaternions to orient objects) seems more like a convention to me, rathen than an intuitive/straight forward approach.

Quaternions are used in rotations, because they can uniquely describe an axis (3-vector) and an amount of rotation around that axis. The only possible way I see, to determine an orientation from a quaternion, is *to make a convention* that the rotation axis should always represent the "look-at" axis of your object (this one is usually the local Z axis), and the remaining scalar part should represent the 'roll angle' of your object around that axis. This is enough information to uniquely describe an orientation in 3d space.

edit:
I'm tired of posting this, but you'll probably need it...

To convert the quaternion to a DCM matrix (orientation) do the following:
Define vectors: localX, localY, localZ to store the object's local axes
localZ = Normalize( quaternion rotation axis {x,y,z} );
localX = cross( localZ, 'unit world up vector' );
localY = cross( localZ, localX );

The orientation matrix will be the product: R*O,
where R is:
[ cos(w) -sin(w) 0 0 ]
[ sin(w) cos(w) 0 0 ]
[ 0 0 1 0 ]
[ 0 0 0 1 ]


and O is:
[ localX.x localY.x localZ.x 0 ]
[ localX.y localY.y localZ.y 0 ]
[ localX.z localY.z localZ.z 0 ]
[ 0 0 0 1 ]

This is the DCM matrix for your object.
If you are using a left-handed system, negate the results of the cross products, and if you work with row-vectors instead of columns, use the transpose of that product.

Btw, have you come across this in physics simulation? I've lately discovered that people often choose this approach, to describe the instantaneous axis of an object's rotation and the angle it has rotated by, with respect to its previous state, when solving for the specific time step.

[Edited by - someusername on January 1, 2006 9:36:18 PM]
Richy2k
Richy2k
Quote:
Original post by Sneftel
First of all, they aren't three imaginary numbers and a real number. They're four real numbers which are used as a single four-dimensional complex number, just as two real numbers can be used as a single two-dimensional


Isnt it 3 complex numbers and 1 real number. W(X, Y, Z): W being the Real number?
Sneftel
Sneftel
A "complex number" is a number in complex space (where complex space has 2, 4, or 8 dimensions) that is not a real number. But yeah, it can be thought of as three imaginary numbers and 1 real number. The reason I refer to it as 4 real numbers is to hammer in the point that there are exactly 4 scalar quantities and that quaternions are thus a 4-dimensional space.
Richy2k
Richy2k
Quote:
Original post by Sneftel
A "complex number" is a number in complex space (where complex space has 2, 4, or 8 dimensions) that is not a real number. But yeah, it can be thought of as three imaginary numbers and 1 real number. The reason I refer to it as 4 real numbers is to hammer in the point that there are exactly 4 scalar quantities and that quaternions are thus a 4-dimensional space.


Thats not the correct way to refer to them, but its probably the easiest way to work them out! Hell its the way I successfully figured them out!
Sneftel
Sneftel
? In what way is that not a correct way to refer to them?
SiCrane
SiCrane
No they aren't. Each quaternion is an element of a four dimensional normed division algebra over the real numbers. Each quaternion can be represented as linear combinations of four basis quaternions 1, i, j and k, but are each themselves single numbers. Much in the same way x + 1 is a single polynomial even though it is composed of two terms x and 1.
Troll
Troll
SiCrane is right on this one. If x, y, and z were complex numbers, you'd be allowed to write a quaternion such as (1, -3.5i, 2+7i, -12.1). You can't. All 4 values must be real-valued.

Now, when talking about complex and hypercomplex numbers, one of the values is referred to as the real part and the others the imaginary part.

You can see the nomenclature in use at Mathworld:
http://mathworld.wolfram.com/Quaternion.html

It clearly states that the 4 numbers are real. It mentions the real & imaginary part. It even shows a representations of quaternions as 4 complex numbers in a 2x2 matrix.
Troll
Troll
Quote:
Original post by someusername
edit:
I'm tired of posting this, but you'll probably need it...

To convert the quaternion to a DCM matrix (orientation) do the following:
Define vectors: localX, localY, localZ to store the object's local axes
localZ = Normalize( quaternion rotation axis {x,y,z} );
localX = cross( localZ, 'unit world up vector' );
localY = cross( localZ, localX );

The orientation matrix will be the product: R*O,
where R is:
[ cos(w) -sin(w) 0 0 ]
[ sin(w) cos(w) 0 0 ]
[ 0 0 1 0 ]
[ 0 0 0 1 ]


and O is:
[ localX.x localY.x localZ.x 0 ]
[ localX.y localY.y localZ.y 0 ]
[ localX.z localY.z localZ.z 0 ]
[ 0 0 0 1 ]

This is the DCM matrix for your object.
If you are using a left-handed system, negate the results of the cross products, and if you work with row-vectors instead of columns, use the transpose of that product.

Btw, have you come across this in physics simulation? I've lately discovered that people often choose this approach, to describe the instantaneous axis of an object's rotation and the angle it has rotated by, with respect to its previous state, when solving for the specific time step.


Since you're tired of posting it anyhow, please don't post it again. I hate to sound mean, but the code you've posted is just plain wrong, and I don't want to see it spread. The code isn't even for quaternions. You're presenting code for an axis-angle representation. Although a quaternion does encode axis-angle information, you won't see calls to sin() and cos() in a quaternion->matrix function since the sine and cosine values are already "encoded" in the 4-tuple.

Another big problem with your code is that it makes an assumption about a world orientation of world-up. This is an unnecessary restriction that leads to all kinds of singularities. Proper handling of orientation with quaternions doesn't require using a world-up vector here and avoids potential singularity issues arising around the up-axis. Converting any quaternion to a matrix in no way requires an external up-vector.

Please just spend a few hours reading up on quaternions. It's well worth the investment. It doesn't take much effort to learn the basics. Once you understand the relationships between vectors and quaternions, life is so much easier and results are so much more robust.
nilkn
nilkn
Quote:
Original post by Sneftel
(where complex space has 2, 4, or 8 dimensions)


Actually, by the Cayley-Dickson construction, you can keep going on and on ad infinitum. But after the sedonions (16-dimensions), things start getting weird (e.g., zero divisors et. al.).
minamur
minamur
my understanding, and i may be way off, is that a quaternion is a hypercomplex number which is analogus to a complex number. quaternions reside in complex space where as complex numbers reside in the complex plane. so it would be fair to refer to a quaternion as a whole as a complex number, or hypercomplex number to be correct. but to say a quaternion contains complex numbers, well that wouldn't be right.

but by refering to them as just four scalers their relationship with complex numbers - and therffffeore how they relate to rotations becomes less clear. maybe that's just me.
haegarr
haegarr
As of my knowledge a quaternion
Q(r,a,b,c) := r*1 + a*i + b*j + c*k
is a complex number of dimension 4, as Sneftel and others have stated already above, where i, j, and k are imaginary numbers, and 1 a real number. Together [1,i,j,k] define the basis of Quaternion space. The values r, a, b, and c are real valued coefficients, giving the coordinates of Q in the quaternion space.

It is similar to Euclidean space: There the basis is given
in 3D: (1 0 0)^T, (0 1 0)^T, (0 0 1)^T
and a vector is build up of adding the weighted basis:
v(x,y,z) := x * (1 0 0)^T + y * (0 1 0)^T + z * (0 0 1)^T
See the similarity with the Q(r,a,b,c) above.

The writing as (x y z)^T is just a convenient method derived from vector calculus. In fact, this kind of writing is arbitrary as long as not also speciying the basis. It is just a common convention.

Quote:
Original post by someusername
Quaternions are used in rotations, because they can uniquely describe an axis (3-vector) and an amount of rotation around that axis. The only possible way I see, to determine an orientation from a quaternion, is *to make a convention* that the rotation axis should always represent the "look-at" axis of your object (this one is usually the local Z axis), and the remaining scalar part should represent the 'roll angle' of your object around that axis. This is enough information to uniquely describe an orientation in 3d space.

A quaternion (to be precise: a _unit_ quaternion) _as a whole_ describes a rotation or an orientation. Here, as well as is the case for rotation matrices, orientation means nothing else than the rotation measured from an origin (what itself could be interpreted as the "identity" rotation but as orientation).

If you restrict the axis implicitely given by a quaternion to the look-at vector is the same as to restrict rotation matrices to represent rotations around the z-axis only. Quaternions definitely allow rotation around arbitrary axis, and hence the axis implicitely given by a quaternion could be oriented anyway.
dragongame
dragongame
Quote:
Original post by nilkn
Quote:
Original post by Sneftel
(where complex space has 2, 4, or 8 dimensions)


Actually, by the Cayley-Dickson construction, you can keep going on and on ad infinitum. But after the sedonions (16-dimensions), things start getting weird (e.g., zero divisors et. al.).


Sorry but as far as my Algbra book goes, the complex numbers (1+i) are a field and quaternion are only a division ring.
And to my knowlage you can't get a division ring with more elements then the quaternion.

Here a link for the math correct defention ( I hope :D ) http://mathworld.wolfram.com/Quaternion.html
“Always programm as if the person who will be maintaining your program is a violent psychopath that knows where you live”
someusername
someusername
@Troll

I think you're misunderstanding my post. Let me remind you (and explain) of some things I've posted.

I wrote in a previous reply
What you suggest, (using quaternions to orient objects) seems more like a convention to me, rathen than an intuitive/straight forward approach.
This means that I believe, in this case, you use a quaternion just because it's compact, not because it's how they were meant to be used in the first place, or because you can do operations on them and come to a 'solution quaternion' to use. I hope you see what I mean. E.g. you can represent an integer with a vector by agreeing to assign each digit to a component. You can do it, it may suit your needs better in some instances, but it doesn't mean that you should replace all integer arithmetics with vector calculus! It's just a temporary convention.

The only possible way I see, to determine an orientation from a quaternion, is *to make a convention* that the rotation axis should always represent the "look-at" axis of your object (this one is usually the local Z axis), and the remaining scalar part should represent the 'roll angle' of your object around that axis. This is enough information to uniquely describe an orientation in 3d space.
This means that you should forget the classic meaning of the quaternion's components and assign each one your own arbitrary interpretation. You only use a quaternion as I described, because it provides four floats in one wrapper, and this is just what you need.

I'm tired of posting this, but you'll probably need it...
I'm obviously not tired of posting anything, that's why I spend so much time in the forum. It was a figure of speech. Sorry if it sounded bad though. I believe it takes me quite long to answer, not only because it's not my native language, but also because I'm trying to clarify as deeply as possible, instead of just posting a comment in vagueness! And my time doesn't come for free either!

However, now that I've been looking into it more deeply, I made a mistake about the matrix I suggested... It's not R*O as I originally posted, it's O*R-1 == O*RT

On the other hand, you posted:

I hate to sound mean, but the code you've posted is just plain wrong, and I don't want to see it spread.

In what way is it wrong when all the above are clear? I wasn't talking about the approach where you integrate the orientation quaternion to find the new orientation. This is a physics engine issue.
What I was trying to describe, is how you can map a unique orientation to a single quaternion, when you've made the convention that you keep its look-at axis in its x,y,z components and an extra roll angle in w. If you're used to quaternion components having a different meaning, I'm sorry, but I wasn't planing on using it as a quaternion in the first place.
The matrix I described, maps the model space local Z axis {0,0,1} to whatever {x,y,z} axis vector you've plugged into the quaternion's x,y,z components and then rotates around it by w rad.
Isn't this a way to express orientation with a quaternion?
Isn't this enough to uniquely define an orientation in space?
For -PI3?
How can it be that it's 'just plain wrong' then? Or 'it shouldn't spread'?

Although a quaternion does encode axis-angle information, you won't see calls to sin() and cos() in a quaternion->matrix function since the sine and cosine values are already "encoded" in the 4-tuple.

Of course you won't. Because in that case you have a unit quaternion that you intend to ultimately turn into a rotation matrix, therefore you've constructed it properly in the first place. (ie. sum of squared components == 1)
In the case I was describing, you don't find the orientation from the quaternion. You just keep the axis in the x/y/z and the angle in w.
The original question was how you can represent orientation with a quaternion.
Am I just wrong, because I'm not saying the same thing you had in mind?

Another big problem with your code is that it makes an assumption about a world orientation of world-up. This is an unnecessary restriction that leads to all kinds of singularities.

I agree. It can create singularities. But it's still one of the most common approaches in creating view matrices/'look at' controllers etc... Also, if you force-normalize the local axes vectors before plugging them into the matrix, it seems to fix most problems. I suppose some checking can be added, to eliminate the problem completely.
However, as posted, it is error prone, I agree.

Please just spend a few hours reading up on quaternions.
At my 25, I'm probably a few months away from signing in for my second degree in mathematics. (state university)
I'm not saying I'm a genius; on the contrary I'm getting rusty on many fields and I had to leave out a big number of interesting subjests -or just "scratch the surface"- due to their wide range.
I just don't think I would have to wait for your prompt to do so in the first place...

What you had in mind was obviously the approach used in physics simulations, where -instead of using the angular velocity vector to integrate the orientation matrix-, you use a quaternion. This is why I asked the OP if he had seen that in a physics simulation, so I could turn the discussion there. I've only learned of the existence of this method while discussing with another poster in this forum one week ago, but I see how it can be realized. Instead of integrating the 3 local axes (vectors in the orientation matrix) you integrate the quaternion axis and apply that instantaneous rotation for the time step directly via the quaternion.

The point is, that the original question was "How can one describe orientation with a quaternion?". I believe what I desribed in my post, was one way. You chose to argue with me, because what I described wasn't the one you had in mind. Instead of just argueing with me, don't you think you should post something -at least- pointing to the "correct" way to this? Just for the poster who had the question in the first place...
If I'm not mistaken, this is the idea.
minamur
minamur
Quote:
Original post by Anonymous Poster
Quote:
Original post by Richy2k
Quote:
Original post by Sneftel
First of all, they aren't three imaginary numbers and a real number. They're four real numbers which are used as a single four-dimensional complex number, just as two real numbers can be used as a single two-dimensional


Isnt it 3 complex numbers and 1 real number. W(X, Y, Z): W being the Real number?


This person is correct, Sneftel. A quaternion is a number which can be said to be made of 3 imaginary and 1 real part.


i think this is a little wrong.

on the one hand you have a quaternion as "3 complex numbers and 1 real number"
which you agree with then you say "3 imaginary and 1 real part".

it seems silly to say but a complex number isn't the same as a complex numbers imaginary part.
Sneftel
Sneftel
Someusername, while you've come up with an interesting way to represent orientations using a 4-scalar representation, that's not how anybody uses quaternions. Everybody I've ever heard of who uses quaternions for rotation uses quaternions the same way, and it's not that way. DirectX's native quaternion class doesn't do it your way; neither does the Java3D quaternion class. Your way has serious problems. Some, such as the arbitrary up-vector and the discontinuities it generates, have already been mentioned. Also, for instance, everybody composes quaternions as qr = q1*q2. Your representation can't do that. Next, normally you can rotate a vector by a quaternion using q*v*q-1. Your representation can't do that.

It's important to recognize that the system by which rotations and quaternions are associated with each other is not arbitrary. If it were, there'd be no real need to call the rotation a quaternion at all, since you couldn't use quaternion operations such as those I listed above. It'd just be a 4-vector. In fact, you wouldn't even do that; you'd just use Euler angles, since your formulation has pretty much the same properties as Euler angles. There's simply no reason at all to use quaternions like that.

Quaternions are not inherently 3-rotations, but they ARE quite good at representing 3-rotations in a particular formulation. Your formulation does not have that property.

Oh, and since you asked for a link to the correct way, let me remind everybody of the Matrix and Quaternion FAQ. Not perfect, but I find myself referring back to it often.
someusername
someusername
OK, it seems I was the one who misunderstood the question in the first place.
I'm sorry... Ignore my previous replies.

@cold_storm
People often choose quaternions instead of matrices to represent orientations of objects while solving physics simulations. This can be done as follows:

You start the simulation by placing all objects in their initial states.
From the initial orientation matrix, calculate the initial orientation quaternion for an object. (using the standard way) This unit quaternion {w,v}={w, {x,y,z}} is of the form {cos(phi/2), sin(phi/2)*v}, where v is a unit vector that represents an axis v and phi is the angle by which the object has to be rotated around v in order to match the new orientation. Call this orientation quaternion o

The torque applied to an object forces (in general) the axis in o to change over time. This change can be calculated by differentiating the quaternion with respect to time, since both the angle phi and axis v depend on time.

Consider the orientation quaternion at time 't1'.
After infitesimal time 'dt', it will have rotated by an angle==|w(t1)|*dt rad around vector w(t1), where w is the angular velocity. Thus at time 't1+dt', the orientation quaternion must be followed by an extra rotation of |w(t1)|*dt rad around the unit axis v=w(t1)/|w(t1)|.
As usual, rotation r2 following rotation r1, can be given by multiplication of the respective quaternions q2*q1.
Therefore, after 'dt' time, the orientation quaternion will be:
o(t1+dt) = {cos(|w(t1)|*dt/2), sin(|w(t1)|*dt/2)*w(t1)/|w(t1)|}*o(t1)

Replacing the 't1+dt' with a time variable 't', produces the formula:
o(t) = {cos(|w(t1)|*(t-t1)/2), sin(|w(t1)|*(t-t1)/2)*w(t1)/|w(t1)|}*o(t1)

Differentiating with respect to 't', and solving for t=t1 gives the derivative of the orientation quaternion at time t==t1: (remember o(t1) is constant)
o'(t1)= {0, (|w(t1)|/2)*(w(t1)/|w(t1)|)}*o(t1)}

Now you can use it to integrate o(t) with respect to time, convert the result to an orientation matrix and apply the result to your mesh. (Look out for any trivial mistakes)

I hope this settles it. And I'm sorry again for the misunderstanding.
timw
timw
I know this question doesn't have any practical signifigance. but what's the take on quaternions being real numbers? to me it seems they can't be real numbers. you're talking of basis vectors, but if you consider just one dimension you have the possibility that the square of a number is negative. this contradicts one of the axiom of the real number system. I'd say it's definitly a field, but not real? what am I missing?

thanks
Tim

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.