Rotation around local axes after translation

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’m probably being daft but I can’t find any examples (red book, angel, gamedev).

Originally posted by grey_area:
[b]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’m probably being daft but I can’t find any examples (red book, angel, gamedev).

[/b]

First of all, did you call

Translatef(-X, -Y, -Z);

after the rotations?

Secondly, what do you mean
“The rotations corrupt each other.”?

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

Hi

That effect is the so called “Gimbal Lock”. I´ve been dealing with It recently. The problem Is that OpenGL modifies the coordinates system when doing a rotation, translation, etc…

There are lots of tutorials on the net that will explain you how to avoid the Gimbal Lock effect.

Because the Gimbal Lock you can face two different problems:

  • Object orientation: I´ve read that you can avoid that changing the rotation order, try rotating first around Z, Y and finally X. For me it works but I haven´t made a strict check yet.

  • Camera orientation: It´s the most uncomfortable effect because you lose a degree of freedom when you try to rotate your camera around the world. I´ve solved the problem using a file I found on the net about “Virtual Trackbals”. Try to find something and If you don´t succeed please write me and I will give you mine that works perfectly.

Hope It works.

First you maybe confused by how the translate and rotate work together.

Think of if you wanted to draw the earth with the moon rotating around it. You would then do the following.

rotate() make a rotation of the earth on its axis.
Draw_earth()
rotate() first rotate moon on its axis
translate() move the moon to it’s orbit.
rotate() rotate the moon around the earth’s axis.
Draw_moon()

(earth)--------(moon)

Hope this helps.

Originally posted by grey_area:
[b]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’m probably being daft but I can’t find any examples (red book, angel, gamedev).

[/b]

[This message has been edited by nexusone (edited 03-26-2002).]

First of all, the first three replies all have errors.

Your code is almost correct. Remember that in OpenGL, transformations are done “locally” and are cumulative. So, after the first glRotate, the coordinate system is rotated and the next glRotate will rotate around the new axes. Think of the rotations like this:

Rotate around X axis == pitch (up/down)
Rotate around Y axis == yaw (left/right)
Rotate around Z axis == roll

Try doing your rotation in the order yaw-pitch-roll (Y-X-Z) instead of pitch-yaw-roll (X-Y-Z). Maybe then it will work the way you expect.

Also, a common mistake is that the angle parameter in glRotate is degrees, not radians.

Coconut - there is no reason to call glTranslate( -x,-y,-z) after rotating if he wants to rotate the model around its local origin. Only if he is rotating around (x,y,z).

jrbcast - His problem is not necessarily gimbal lock and the source of gimbal lock is not because “OpenGL modifies the coordinate system”. Here is a example of the problem of gimble lock:

  1. Stand up if your chair doesn’t spin.
  2. Pitch your head up 90 degrees. p=90,y=0,r=0. — You are looking straight up.
  3. Roll CW 90 degrees. p=90,y=0,r=90. — You are still looking straight up but now you have turned to the left.
  4. Pitch down 90 degrees. p=0, y=0, r=90.

You are now looking to the left of your original direction with your head straight (as if p=0,y=90,r=0), but according to your Euler angles (p=0, y=0, r=90), you should be looking in your original direction with your head tilted over to the right.

There are two ways to fix this.

  1. Use a rotation matrix or quaternions to keep track of orientation.
  2. Allow only one angle (typically yaw) to go up to (and beyond) +/- 90 degrees.

nexusone - You are definitely confused about how translate and rotate work together in OpenGL. Here is the correct sequence:

Rotate for the earth’s rotation
Draw the earth
Undo the rotation (using glPopMatrix)
Rotate for the moon’s revolution around the earth
Translate out to the moon’s orbit
Rotate for the moon’s rotation
Draw the moon

There is an example just like this in the red book Chapter 3, “Building a Solar System”

take a look at the thread “Rotation Around Local Axes” in the advanced forum, i posted some code there

eik

You just wrote every thing in the same order as I did, I was showing the order of things.
As to explane how things work…

Of course I know in a real program you would have to use popmatrix!!!

Originally posted by Jambolo:
[b]First of all, the first three replies all have errors.

nexusone - You are definitely confused about how translate and rotate work together in OpenGL. Here is the correct sequence:

Rotate for the earth’s rotation
Draw the earth
Undo the rotation (using glPopMatrix)
Rotate for the moon’s revolution around the earth
Translate out to the moon’s orbit
Rotate for the moon’s rotation
Draw the moon

There is an example just like this in the red book Chapter 3, “Building a Solar System”[/b]

Hi,

I´ve just read your answer and I want to make you a question:

In my program I need to rotate elements on my scene using Euler angles…so my question is, Will the gimbal lock problem appear wathever is the order I make rotations?. Actually I do Z,Y,X and It seems to work but as I haven´t tried all possible combinations I am not sure If it will work properly. Can you answer that?.

Thanks.(For the rectification to).

Originally posted by jrbcast:
In my program I need to rotate elements on my scene using Euler angles…so my question is, Will the gimbal lock problem appear wathever is the order I make rotations?. Actually I do Z,Y,X and It seems to work but as I haven´t tried all possible combinations I am not sure If it will work properly. Can you answer that?.

Gimbal lock is caused by using Euler angles to keep track of orientation. It doesn’t matter which order the angles are applied.

Originally posted by nexusone:

rotate() make a rotation of the earth on its axis.
Draw_earth()
±—>rotate() first rotate moon on its axis
| translate() move the moon to it’s orbit.
±—>rotate() rotate the moon around the earth’s axis.
Draw_moon()

nexusone, you need to swap these two lines.

[This message has been edited by Jambolo (edited 03-28-2002).]

You are correct I did need to swap the two lines. I put together a simple program, for an example:

Originally posted by Jambolo:
[b] nexusone, you need to swap these two lines.

[This message has been edited by Jambolo (edited 03-28-2002).][/b]

#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

static int hour = 0, day = 0, week = 0;

void init(void)
{

glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH);

}

void display(void)
{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
glMatrixMode(GL_MODELVIEW);

glTranslatef(0, 0, -10);
glColor3f( 0.0, 0.0, 1.0);
glPushMatrix();
glRotatef(hour, 0, 1, 0);
glRotatef( 90, 1, 0, 0);
glutWireSphere( 2, 16, 8);
glPopMatrix();

glTranslatef(0, 0, -10);
glPushMatrix();
glRotatef(week, 0, 1, 0);
glRotatef( 90, 1, 0, 0);
glTranslatef( 4, 0, 0);
glRotatef(day, 0, 0, 1);
glColor3f( 0.5, 0.5, 0.5);
glutWireSphere(0.5, 16, 8);
glPopMatrix();

glutSwapBuffers();
}

void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60.0,(GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}

void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case ‘D’:
day = day + 15;
if (day > 360) day = 0;
glutPostRedisplay();
break;
case ‘W’:
week = week + 10;
if (week > 360) week = 0;
glutPostRedisplay();
break;
case ‘H’:
hour = hour + 15;
if (hour > 360) hour = 0;
glutPostRedisplay();
break;
case 27:
exit(0);
break;
default:
break;
}

}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (10, 10);
glutCreateWindow (argv[0]);
glutSetWindowTitle(“Glutplanets”);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

[This message has been edited by nexusone (edited 03-28-2002).]