trouble understanding quaternions

Started by
19 comments, last by okonomiyaki 18 years, 10 months ago
Quaternions are somewhat simple. I could use them right now in my program if I wanted to, but honestly I'm not sure how exactly it works. A quaternion is basically an extension of the common complex number (x,yi), correct? A common representation would be (w, (xi, yj, zk)). I can understand how quaternions are multiplied, etc, because it follows the common rules of complex number algebra. I guess I don't quite understand how they relate to the real-world 3d coordinate system. I suppose it's the imaginary part that I don't quite understand. I know what an imaginary number is (i*i = -1), but what implications does the imaginary part have on the quaternion? Could somebody explain "complex number space" to me, and what part the imaginary part plays? I found this conversion routine off of this article: -- If the axis of rotation is (ax, ay, az) and the angle is theta (radians) then the angle= 2 * acos(w) ax= x / scale ay= y / scale az= z / scale where scale = sqrt (x2 + y2 + z2) -- It seems to me that it's basically normalizing the (x,y,z) component as you would a regular 3d vector. What happened to the imaginary part? Don't you have to cancel it out in some way? Or is it that when you normalize a quaternion (by the normal q = q/ |q|) that it happens to "align" with 3d space? If so, what's the conceptual basis for this?
Advertisement
It is very useful to think of a quaternion as an encoded axis-angle representation, but conversion from quat to axis-angle doesn't give you much insight. Here is how to convert from axis-angle (a,t) to quat (x,y,z,w):

q.x = a.x * sin(t/2)
q.y = a.y * sin(t/2)
q.x = a.z * sin(t/2)
q.w = cos(t/2)

Q = q.xi + q.yj + q.zk + q.w

As you can see, the imaginary components are all scaled by the same value, so when converting to axis-angle, simply normalizing them gives you the axis. You could also scale it by sqrt(1-q.w2), which is slightly faster.

BTW, rotations are represented by unit quaternions (|Q| == 1).
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Interesting. Thanks for the info. It's getting clearer. and yeah, I knew about the unit quaternion rule. Just trying to figure out why. I'm assuming it's something like homogenous coordinates, which really deals with 4d space until the 4th component is 1, in which it aligns with 3d space. It's probably something like that (some weird complex number space).

Anyway, I have a lot better grasp now after thinking about it more. I'm implementing a camera system to help me learn them.

One last question though. What's the best way to transform a 3d vector by a quaternion? Say I have a quaternion that represents my current orientation, and I want the x-axis of my local viewing orientation. You can extract the matrix from the quat, tranform (1,0,0) by it, but that's quite a lot of operations. Is there an easier way?

Thanks a lot for the help.
After reading this from mathworld:
http://mathworld.wolfram.com/EulerParameters.html

I guess using unit quaternion for rotation is related to this:

http://mathworld.wolfram.com/EulerParameters.html
Quote:Original post by okonomiyaki
One last question though. What's the best way to transform a 3d vector by a quaternion? Say I have a quaternion that represents my current orientation, and I want the x-axis of my local viewing orientation. You can extract the matrix from the quat, tranform (1,0,0) by it, but that's quite a lot of operations. Is there an easier way?


If you just want the x-axis, you don't need to multiply by (1,0,0) once you've generated the matrix. The first column vector of the matrix is the x-axis, and generating the matrix is a pretty cheap operation.

Alternatively, you can treat the vector as a quaternion with a w-component of 0 and do a normal quat * quat transformation.

Personally, I would convert to matrix, then multiply. If there's one good thing about matrices, it's that their orientation is easy to visualize since the coordinate axes are right there. Nice little sanity check since quats are notoriously unintuitive to visualize.

Quote:Original post by okonomiyaki
I knew about the unit quaternion rule. Just trying to figure out why.

Because constraining the quaternion so that it has a length of 1 prevents any scaling during the rotation. A unit quaternion can be thought of as a point on the surface of a unit sphere. This is exactly why quaternions are so useful, interpolating between them is interpolating between 2 points on the sphere, whereas interploation rotation matrices would be like drawing a straight like between the 2 points (thus cutting inside the sphere, and not producing the expected rotations).

Quote:One last question though. What's the best way to transform a 3d vector by a quaternion? Say I have a quaternion that represents my current orientation, and I want the x-axis of my local viewing orientation. You can extract the matrix from the quat, tranform (1,0,0) by it, but that's quite a lot of operations. Is there an easier way?

You can apply the rotation directly to the vector like this:
v' = q*v*q-1
where v is the quaternion (w=1, x=vx, y=vy, z=vz)
and q is your rotation quaternion

However, this is useless if you want to concatonate the rotation with other transformations or send it to the gfx card, so when you're reading to apply the rotation to 3d points you'll normally convert it to a rotation matrix.


EDIT: Btw, quaternions are far wierder than i*i=-1

i*i = -1
j*j = -1
k*k = -1
i*j = k
j*i = -k
j*k = i
k*j = -i
k*i = j
i*k = -j

...or something like that [smile]
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
If you want to understand the math behind quaternions, I'd suggest looking at the 2D analogue: simple complex numbers. Simple complex numbers can be used to represent rotations in the 2D plane. Consider the case where you represent an angle θ as a complex number using the formulae

f(θ)=cos θ + isin θ
f-1(c)=atan2(cimag, creal)

Notice, BTW, that I'm cheating a bit with the second formula by using C functions. The full algorithm is a bit complicated. Don't worry about it, though.

Bingo: you end up representing an angle as a real part and a single imaginary component. If you want to graph this complex number, you might choose to split it into its two components, put the real component as the X axis and the imaginary component as the Y axis, and treat it as a 2D vector. When you're treating it like this, you'll notice that the complex numbers generated by feeding all angles into the above formula all fall on the unit circle.

Now think about combining rotations. First, notice that f(0) = 1. (Or, if you prefer, 1 + 0i.) And notice that any complex number multiplied by 1 is itself. That's the analogue of multiplying by the multiplicative identity quaternion. Also note that any integral multiple of 2π will produce the identity complex number, showing how the angles "wrap around".

Play around with this system a bit; in particular, multiplying arbitrary rotations by f(π/2) and f(π). It really has most of what quaternions do, in a more accessible arena.
Quote:Original post by ajas95
Personally, I would convert to matrix, then multiply. If there's one good thing about matrices, it's that their orientation is easy to visualize since the coordinate axes are right there. Nice little sanity check since quats are notoriously unintuitive to visualize.


Hm.. ok, that should be too hard. I'll just synch the matrix with the quaternion when I need to, and simply read from the matrix. That should be pretty fast.

Quote:
Because constraining the quaternion so that it has a length of 1 prevents any scaling during the rotation.


Ah, ok.. I got it.

Quote:
If you want to understand the math behind quaternions, I'd suggest looking at the 2D analogue: simple complex numbers. Simple complex numbers can be used to represent rotations in the 2D plane. Consider the case where you represent an angle θ as a complex number using the formulae


I was looking at simple complex numbers at first, but I had no idea you could represent rotations with simple complex numbers. Thanks, I googled about it and found some more resources. It's all.. very strange to visualize, but I guess you shouldn't try to visualize it. Seeing rotations with complex numbers helped a lot though.

Thanks guys
Man, I hate to bump this, but this is killing me. I figured it'd be better to post here than to make a whole new thread...

Why doesn't this work? I've fiddled around with it in all ways possible.. I got the camera system working doing it a different way, but I like doing it this way and plus I just want to know what's wrong so that I can understand quaternions better.

Basically you call rotateXAxis and rotateYAxis to orientate the camera. In rendering it simply converts the quaternion to a matrix and loads it in OpenGL.

But these functions produce quirky results:

void camera::rotateXAxis(float ang) {	float *m = quatToMatrix(quatView);	float axisX = m[0];	float axisY = m[1];	float axisZ = m[2];	quatView = axisAngleToQuat(axisX, axisY, axisZ, ang) * quatView;}void camera::rotateYAxis(float ang) {	float *m = quatToMatrix(quatView);	float axisX = m[4];	float axisY = m[5];	float axisZ = m[6];	quatView = axisAngleToQuat(axisX, axisY, axisZ, ang) * quatView;}


The matrix is column-major, so that should extract the local axes right? And then you simply rotate around it a little, and apply the rotation... seems simple enough. What's wrong?

I printf'd each axis when it rotates it. Say I start facing (0.0f, 0.0f, -1.0f). As I start looking down, the y-axis should start rotating downward towards the -z axis. However, the y-axis I get from the matrix is *positive* z, so it seems like it rotates the opposite way. I'm a little confused, can anyone clarify this? Thanks!

Edit: Also, I tried multiplying it in the different order, but it didn't help.
Can you post your quatToMatrix() code?

What I'm worried about is the statement:

float *m = quatToMatrix(quatView);

which implies you're creating a local matrix in quatToMatrix then returning a pointer to it... which is one of those "really bad" things.

Another thing. When you talk about swapping the order, I would say that you should swap the order for rotateX, but leave it the same for rotateY (yaw happens around world y-axis, pitch happens around local x-axis).

This topic is closed to new replies.

Advertisement