Rotation Around Local Axes

Hi - I want to rotate my model around it’s local axes (over multiple frames) after a translation:

Translatef(X, Y, Z);
Rotatef(thetaX, 1.0, 0.0, 0.0);
Rotatef(thetaY, 0.0, 1.0, 0.0);
Rotatef(thetaZ, 0.0, 0.0, 1.0);

It doesn’t work. The rotations corrupt each other. I think I need the correct updated local vectors for the model’s XYZ axes but how do I get those?

I am assuming that your vertices are stored in the local coordinate system. You must transform them by the local system first. One of the main reasons why opengl uses column major matrices is that Concatenation is in reverse order. Which allows you to go pushing and poping in a much better way.

I am not sure what you mean by Translate. I am guessing that the glTranslatef(X, Y, Z); translates from the local to the world coordinates. And that the rotation is local. Please clarify and check your order of operations. I would want to say that the rotations should be first before the Translation. But also remember the complications of rotating around all 3 axis’s. Euler angles can cause rather unexpected results.

Let me know if this helps. I feel like I wasn’t very clear but I don’t really want to get head of heals into a ton of vector, rotation, and matrix math.

But if you like I will.

use these functions for rotating:

you need 2 4x4 matrices for this.

GLdouble mat[16];
GLdouble invmat[16];

the inverse matrix is used for camera translation, so if you want to view from the perspective of the object you’re translating, feed your camera object with the inverse matrix and do

glMultMatrixd(invmat);
glTranslatef(-x, -y, -z);

ok now the rotation functions:

void matxrot(GLdouble *mat, GLdouble *invmat, GLfloat rot)
{
GLdouble c=cos(grad2rad(rot));
GLdouble s=sin(grad2rad(rot));
GLdouble tmp[16],tmp1[16],tmp2[16];

tmp[0]=1; tmp[1]=0; tmp[2]=0; tmp[3]=0;
tmp[4]=0; tmp[5]=c; tmp[6]=s; tmp[7]=0;
tmp[8]=0; tmp[9]=-s; tmp[10]=c; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(mat,tmp,tmp1);

tmp[0]=1; tmp[1]=0; tmp[2]=0; tmp[3]=0;
tmp[4]=0; tmp[5]=c; tmp[6]=-s; tmp[7]=0;
tmp[8]=0; tmp[9]=s; tmp[10]=c; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(tmp,invmat,tmp2);

for(int i=0;i<16;i++)
{
	mat[i]=tmp1[i];
	invmat[i]=tmp2[i];
}

}

// y rotation relative to current orientation

void matyrot(GLdouble *mat, GLdouble *invmat, GLfloat rot)
{
GLdouble c=cos(grad2rad(rot));
GLdouble s=sin(grad2rad(rot));
GLdouble tmp[16],tmp1[16],tmp2[16];

tmp[0]=c; tmp[1]=0; tmp[2]=-s; tmp[3]=0;
tmp[4]=0; tmp[5]=1; tmp[6]=0; tmp[7]=0;
tmp[8]=s; tmp[9]=0; tmp[10]=c; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(mat,tmp,tmp1);

tmp[0]=c; tmp[1]=0; tmp[2]=s; tmp[3]=0;
tmp[4]=0; tmp[5]=1; tmp[6]=0; tmp[7]=0;
tmp[8]=-s; tmp[9]=0; tmp[10]=c; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(tmp,invmat,tmp2);

for(int i=0;i<16;i++)
{
	mat[i]=tmp1[i];
	invmat[i]=tmp2[i];
}

}

// z rotation relative to current orientation

void matzrot(GLdouble *mat, GLdouble *invmat, GLfloat rot)
{
GLdouble c=cos(grad2rad(rot));
GLdouble s=sin(grad2rad(rot));
GLdouble tmp[16],tmp1[16],tmp2[16];

tmp[0]=c; tmp[1]=s; tmp[2]=0; tmp[3]=0;
tmp[4]=-s; tmp[5]=c; tmp[6]=0; tmp[7]=0;
tmp[8]=0; tmp[9]=0; tmp[10]=1; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(mat,tmp,tmp1);

tmp[0]=c; tmp[1]=-s; tmp[2]=0; tmp[3]=0;
tmp[4]=s; tmp[5]=c; tmp[6]=0; tmp[7]=0;
tmp[8]=0; tmp[9]=0; tmp[10]=1; tmp[11]=0;
tmp[12]=0; tmp[13]=0; tmp[14]=0; tmp[15]=1;

matmultrot(tmp,invmat,tmp2);

for(int i=0;i<16;i++)
{
	mat[i]=tmp1[i];
	invmat[i]=tmp2[i];
}

}

the 3rd parameter is always used to store the result matrix.
matmultrot is just a standard matrix multplication.

now this is how to move and rotate your object:

  1. set both matrices to identity

  2. rotate left/right:
    rotatey(mat,invmat,angle_increment);

  3. up/down: use rotatex

  4. roll left/right: use rotatez

  5. move forward/backward in respect to your orientation:

GLfloat dx=-mat[8];
GLfloat dy=-mat[9];
GLfloat dz=-mat[10];

x+=(dx)*spd;
y+=(dy)*spd;
z+=(dz)*spd;

where spd is your movement speed.
ah yes, set t identity only for initializing. if you want to control your camera directly using this, use invmat for 5) and mat for glMutlMatrixd

hope this was clear
eik

[This message has been edited by hoshi55 (edited 03-25-2002).]

ah by the way, ‘grad2rad’ is just a little routin to convert degree to radians.

GLdouble grad2rad(GLdouble x)
{
return x*0.017453292;
}

I’m assuming that your matmultrot function does (very pseudo)

tmp.invmat

and returns the result in tmp2.

Once I’ve implemented this function I’ll try and get the whole thing working. Will get back to you with results.

basically the function does m1.m2, yes. but it never multiplies mat with invmat, that would make no sense (see code above)
for convenience here’s the matmultrot function. it’s optimized for rotations ONLY so it does not work for translations!

// rotation optimized matrix multiplication

void matmultrot(GLdouble *mat1, GLdouble *mat2, GLdouble *tmp)
{
tmp[0]=mat1[0]*mat2[0]+mat1[4]*mat2[1]+mat1[8]*mat2[2];
tmp[1]=mat1[1]*mat2[0]+mat1[5]*mat2[1]+mat1[9]*mat2[2];
tmp[2]=mat1[2]*mat2[0]+mat1[6]*mat2[1]+mat1[10]*mat2[2];
tmp[4]=mat1[0]*mat2[4]+mat1[4]*mat2[5]+mat1[8]*mat2[6];
tmp[5]=mat1[1]*mat2[4]+mat1[5]*mat2[5]+mat1[9]*mat2[6];
tmp[6]=mat1[2]*mat2[4]+mat1[6]*mat2[5]+mat1[10]*mat2[6];
tmp[8]=mat1[0]*mat2[8]+mat1[4]*mat2[9]+mat1[8]*mat2[10];
tmp[9]=mat1[1]*mat2[8]+mat1[5]*mat2[9]+mat1[9]*mat2[10];
tmp[10]=mat1[2]*mat2[8]+mat1[6]*mat2[9]+mat1[10]*mat2[10];
tmp[3]=0;
tmp[7]=0;
tmp[11]=0;
tmp[12]=0;
tmp[13]=0;
tmp[14]=0;
tmp[15]=1;
}

eik

[This message has been edited by hoshi55 (edited 03-27-2002).]