tags:

views:

63

answers:

2

I have my object's rotation and translation in a quaternion, which I've converted to a matrix[16].

How do I feed that matrix to OpenGL? I'd-a thought I could just glLoadMatrix() with my new, fancy-pants matrix and all would be good, but I'm getting a blank screen.

(I'm a bit of a GL n00b, so type slowly and use small words ;)

My code looks something like this:

glPushMatrix();

[quaternion makeIdentity];         // reset quat
[quaternion setPitch: rotation.x yaw: rotation.y roll: rotation.z];  // Set up with rotation coords (NOTE: setPitch:yaw:roll: is smart about degrees->radians)

GLdouble matrix[16];
[quaternion matrix: &matrix[0]];   // get quat -> matrix
matrix[12] =  location.x;          // fill in the translation
matrix[13] =  location.y;
matrix[14] =  location.z;

glLoadMatrixd(matrix);

glScaled(scale.x, scale.y, scale.z);

// draw geometry here -- snip

glPopMatrix();

I think I'm pretty close but, when I use this code, I get a blank display (everything is glClearColor.)

NOTE: when I skip the quaternion part and do something like this:

glPushMatrix();

glTranslatef(location.x, location.y, location.z);

glRotated(rotation.z,   0,   0, 1.0);
glRotated(rotation.x, 1.0,   0,   0);
glRotated(rotation.y,   0, 1.0,   0);

// draw geometry here -- snip

glPopMatrix();

the display is as expected. The only problem is that my rotations are screwy, due to being applied sequentially. Hence my desire to use quaternions.

+2  A: 

If you don't forgot to set current matrix mode to GL_MODELVIEW, your matrix should be loaded correctly. Check your quat -> matrix calculations. I'd start from rotation by zero angle and comparing result with identity matrix.

alxx
Ok, coding to the identity matrix, I found a couple of bugs (reversed signs) in the matrix calculations that I got off a web-site. Can you suggest an authoritative place to get correct quat -> glMatrix formulae?
Olie
Maybe this - http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm - (there is code for 4x4 matrix, too) - and remember that GL matrix are column-major.
alxx
+1  A: 

Quaternions don't have a translation part. The translation must be maintained separately, as is the case in the second code snippet.

I'm not sure the code will do what's desired, anyway. Quaternions won't solve gimbal lock, if the problem is being stated in the very way that introduces gimbal lock in the first place. If the quaternion is being set afresh from pitch/yaw/roll each frame, there will be the same problems as before, and for the same reasons. (And if it appears that's not the case, that's because the quaternion construction code is doing the same thing that the matrix construction code could do, but in this case doesn't: rotating about each rotated axis in turn, rather than rotating about a fixed one.)

To fix this, maintain a quaternion as part of the object's state, and apply each rotation to it directly. This doesn't really buy one much that couldn't be done just as easily with a matrix, though. (I haven't counted the operations, so that's not so say that it may turn out to be rather more efficient one way rather than the other.)

The main advantage of quaternions is that it's easy to interpolate between them, getting something reasonable at each intermediate step, simply by summing the weighted inputs and normalizing the result. SLERP is also an option. The equivalent operation on matrices comes unstuck in certain situations (e.g., with two matrices representing opposing orientations, you'll end up with a column consisting entirely of zeros...), and trying to do something similar with pitch/yaw/roll just generates a big mess.

As for turning one into a matrix, if you've got a quaternion whose vector part is (qx,qy,qz) and whose scalar part is qw, you can turn it into an OpenGL matrix using code like this:

mtx[0]=1.f-2.f*qy*qy-2.f*qz*qz;
mtx[1]=0.f+2.f*qx*qy+2.f*qw*qz;
mtx[2]=0.f+2.f*qx*qz-2.f*qw*qy;
mtx[3]=0.f;

mtx[4]=0.f+2.f*qx*qy-2.f*qw*qz;
mtx[5]=1.f-2.f*qx*qx-2.f*qz*qz;
mtx[6]=0.f+2.f*qy*qz+2.f*qw*qx;
mtx[7]=0.f;

mtx[8]=0.f+2.f*qx*qz+2.f*qw*qy;
mtx[9]=0.f+2.f*qy*qz-2.f*qw*qx;
mtx[10]=1.f-2.f*qx*qx-2.f*qy*qy;
mtx[11]=0.f;

mtx[12]=0.f;
mtx[13]=0.f;
mtx[14]=0.f;
mtx[15]=1.f;

The above was search-and-replace-ed into the above form, so I really hope I didn't screw it up.

brone
Whilst I am here I suppose I should add that another advantage of a quaternion is that it is only 4 floats, rather than 9. (Or 12, or whatever.)
brone