Wednesday, 1 August 2012

How to rotate in 3D using OpenGL the proper way.

So if your doing any sort of OpenGL or something that requires rotating an object in 3D, you will come across a problem where you cant rotate an object properly. What I mean by properly is that when the object rotates, the axes seem to rotate with it, and your rotation looks odd/is wrong. What you are suffering from is probably a phenomenon called Gimbal Lock. Since I've been doing ios development, im going to show you this in OpenGL/GLK and objective-c.

Step1: create an up, front and right vector for your object, these will point to the front, right and upward direction of your object, so initialise them like so:

right = GLKVector3Make(1, 0, 0);
up = GLKVector3Make(0, 1, 0);
front = GLKVector3Make(0, 0, 1);

You can initialise them differently (maybe you want front to be (0, 0, -1)), but these basically just represent the axes of rotation.

Step 2: Setup some methods to do rotations on these vectors, you would need 3 methods like this to do each axis, this is just the X axis.

- (void) rotateXInDegrees:(float)rot{

    GLKMatrix3 temp = GLKMatrix3MakeRotation(GLKMathDegreesToRadians(rot), 1, 0, 0);

    right = GLKMatrix3MultiplyVector3(temp, right);
    up = GLKMatrix3MultiplyVector3(temp, up);
    front = GLKMatrix3MultiplyVector3(temp, front);
}

Step 3: here is the elegant part, in your update method basically copy paste this matrix (in the code the parameters are flipped to what it actually is in mathematical terms, but that's just how the parameters for this matrix function are set out)

mvm = GLKMatrix4Make(right.x,    right.y,    right.z,    0,
                     up.x,       up.y,       up.z,       0,
                     front.x,    front.y,    front.z,    0,
                     position.x, position.y, position.z, 1);

You can leave out the position vector in that matrix if you dont plan on moving the object, just replace it with 0's. The reason for this matrix is explained here: http://www.songho.ca/opengl/gl_anglestoaxes.html
this matrix will orient your object according to the vectors you have setup and throw in a translation for free!

Step4: multiply this matrix with you modelview matrix in your draw function.
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, mvm);

Here mvm is your objects local modelViewMatrix and modelViewMatrix is your global (or camera) modelViewMatrix

And thats it! Just use the functions you made to do rotations and this magic matrix will take care of all your rotational needs.