1

So I have a cube that I wish to rotate around any of its three axes (the axes of the cube, not the window). As many other similar questions have stated, my rotations work as long as I am only rotating in one direction, but when I start mixing them, I get strange results. In particular, the rotation about the y-axis always rotates about the y-axis of the window, regardless of how the cube has been rotated.

My drawing code is as follows:

glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity();
gluLookAt(0.0, 5.0, 15.0,  
          0.0, 0.0, 0.0,  
          0.0, 1.0, 0.0);
glPushMatrix();
glRotatef(theta_y,0,1,0); 
glRotatef(theta_x,1,0,0);
glRotatef(theta_z,0,0,1);
draw_cube();
glPopMatrix();

This question seems to describe pretty much exactly what I am trying to do, and the accepted answer seems to be what I want to do, however the link he provides is dead.

From what I can gather in the linked question, my z-rotation is performed first, which means in my x-rotation (which would be next) I need to, instead of rotating about (1,0,0), I would rotate about (-sin(theta_z),cos(theta_z),0). But then for the third rotation, he only gives the link, saying it gets "very complicated." Now that the link is dead, I'm not sure how to go about this third rotation.

EDIT: Based on the replies, I have added three vectors: cube_x, cube_y, and cube_z to hold the current axes of my cube.They are initialized as follows:

float cube_x[] = {1.0f,0.0f,0.0f,0.0f};
float cube_y[] = {0.0f,1.0f,0.0f,0.0f};
float cube_z[] = {0.0f,0.0f,1.0f,0.0f};

Back in my drawing function, I have changed it so that the rotations are done around these axes rather than the global axes as I had previously. After performing the three rotations, I call glGetFloatv to get the current matrix and use a new function, update_vector to fill my cube vectors with their new values. This all is included below:

void update_vector(float vector[],float matrix[]) {
    vector[0] = matrix[0]*vector[0] + matrix[1]*vector[1] + matrix[2]*vector[2] + matrix[3]*vector[3];
    vector[1] = matrix[4]*vector[0] + matrix[5]*vector[1] + matrix[6]*vector[2] + matrix[7]*vector[3];
    vector[2] = matrix[8]*vector[0] + matrix[9]*vector[1] + matrix[10]*vector[2] + matrix[11]*vector[3];
    vector[3] = matrix[12]*vector[0] + matrix[13]*vector[1] + matrix[14]*vector[2] + matrix[15]*vector[3];

}

void my_display(void) {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) ;

    glMatrixMode(GL_MODELVIEW) ;
    glLoadIdentity();
    gluLookAt(0.0, 5.0, 15.0,  
          0.0, 0.0, 0.0,  
          0.0, 1.0, 0.0); 
    glPushMatrix();
    glRotatef(theta_y,cube_y[0],cube_y[1],cube_y[2]); 
    glRotatef(theta_x,cube_x[0],cube_x[1],cube_x[2]);
    glRotatef(theta_z,cube_z[0],cube_z[1],cube_z[2]);

    //get the current matrix
    float my_matrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, my_matrix);

    //Multiply the matrix by each of my vectors
    update_vector(cube_x,my_matrix);
    update_vector(cube_y,my_matrix);
    update_vector(cube_z, my_matrix);

    make_cube();
    glPopMatrix();

    /* buffer is ready */
    glutSwapBuffers();

    return ;
}

Now when I try to rotate about the y axis, the cube seems to wobble around along a few axes for a little bit before finally settling into a rotation about the x-axis. Rotating about Z does the same thing. Only rotating about the x-axis seems to work.

EDIT: SOLUTION:

In his comment below, Gavin mentioned that the Y-axis rotation was always happening first. This is the whole issue. By adding a flag ROT and setting it based on which axis I am attempting to rotate around, I am able to order the rotations so that the axis being rotated about is done last.

Community
  • 1
  • 1
sven
  • 121
  • 4
  • 11
  • 1
    Here is a link to the article you said was dead [Rotation About an Arbitrary Axis in 3 Dimensions](http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/) – dmitri Oct 10 '14 at 07:11
  • possible duplicate of [how to rotate all objects by their own centers and then translate them to the real position (it isn't working)](http://stackoverflow.com/questions/25974144/how-to-rotate-all-objects-by-their-own-centers-and-then-translate-them-to-the-re) – Spektre Oct 13 '14 at 07:42

2 Answers2

1

After your LookAt you must translate by the negative position of the cube, do the rotations, then translate back to the cube's position.

Gavin Simpson
  • 2,766
  • 3
  • 30
  • 39
  • So if my cube is centered at the origin (opposite corners at [1,1,1] and [-1,-1,-1]) and my lookat is at position (0,5,-15), then I first translate (0,-5,15), rotate, translate (0,5,-15), then draw the cube? – sven Oct 10 '14 at 15:04
  • I was actually thinking this might have something to do with it. After the lookat, I translate (0,5,-15) and a check of GLGetFloatv tells me that I am now at the origin (the last 4 elements are 0,0,0,1).I perform my rotations as written above, translate (0,-5,15) to get back to where my matrix was previously, and then pop my matrix. When I run this, however, I appear to be zoomed way in on the cube, with no other changes. – sven Oct 10 '14 at 15:08
  • Hmm, I think you may be just a bit confused about order of rotations. The original code you posted runs fine, ie as I would expect. Just put the "pushmatrix" before the lookat. Perhaps you just need to change the order of rotation, as the Y rot will always happen first in your code, and as you are pushing and poping the matrix it will always, by coincidence, be the same as screen orientation. I hope that makes sense. – Gavin Simpson Oct 10 '14 at 15:37
  • glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); gluLookAt(0,0.5,-5,0,0,0,0,1,0); glRotatef(theta, 0.0f, 0.0f, 1.0f); glRotatef(theta, 0.0f, 1.0f, 0.0f); glRotatef(theta, 1.0f, 0.0f, 0.0f); drawcube(); glPopMatrix(); – Gavin Simpson Oct 10 '14 at 15:43
  • Putting the push before the lookat makes it work as it initially did. In this state, I am able to rotate the cube along its x-axis or it's z-axis, but I can't rotate it on it's y; it simply rotates around the window's y-axis, rather than the axis running through the cube's sides which initially faced (0,1,0) and (0,-1,0), respectively – sven Oct 10 '14 at 15:52
  • Perhaps the initial screen setup is not right, i.e. in your resizeGL function? The code as I posted runs 100%. with the following in the WM_SIZE message (assuming win32) - GLvoid ReSizeGLScene(GLsizei m_width, GLsizei m_height) { if (m_height==0) { m_height=1; } glViewport(0,0,(GLsizei)m_width,(GLsizei)m_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)m_width/(GLfloat)m_height,0.01f,250.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } – Gavin Simpson Oct 10 '14 at 16:00
  • So it turns out the issue what something you mentioned in your first comment, that the Y-rotation was always done first. Somehow I overlooked that. Basically what I did was add a flag for what axis was being rotated on, and used a switch to ensure that that axis was rotated last. – sven Oct 10 '14 at 16:11
  • Well I played with it some more and it turns out this solution is not quite perfect. I can rotate the cube along its various axes, and it works for a little while, but it starts to "jump" when I try to switch directions. For example, I'll rotate it around the y, then around the x. Then around the y again. When I try to switch back to the x-axis, it jumps to a different point of rotation and rotates from there, often leaving the axis of rotation completely – sven Oct 10 '14 at 18:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62842/discussion-between-gavin-simpson-and-user3035026). – Gavin Simpson Oct 10 '14 at 18:06
0

I don't know what's supposed to be complicated. OpenGL does the matrix math for you. Remember matrix multiplication is associative so if Rx etc are rotations about the coordinate axes, then Rx.Ry means rotate about y then x. It's always about the coordinate axes no matter where your shape has ended up in the meantime. BTW, OpenGL ES is right handed, unlike traditional OpenGL.

Adrian May
  • 2,127
  • 15
  • 24