GarrickW
GarrickW

Reputation: 2239

OpenGL Rotation - Local vs Global Axes

So I've got an object I'm trying to rotate according to a Yaw, Pitch and Roll scheme, relative to the object's own local axes rather than the global space's axes. According to this, I need to perform the rotations in that order. I've interpreted that to mean this:

glRotatef(m_Rotation.y, 0.0, 1.0, 0.0);
glRotatef(m_Rotation.z, 0.0, 0.0, 1.0);
glRotatef(m_Rotation.x, 1.0, 0.0, 0.0);

However, rotation around the Y and Z axes don't work. Rotation around the Y axis is always relative to the global space, and rotation around the z axis works of the rotation around the X axis is 0, but otherwise messes up.

Just to be sure, I tried the reverse order as well, but that doesn't work either. I think I've tried all the other orders as well, so the problem must be something else. might it be?

This is how I obtain the rotations:

    ///ROTATIONS
    sf::Vector3<float> Rotation;
    Rotation.x = 0;
    Rotation.y = 0;
    Rotation.z = 0;
    //ROLL
    if (m_pApp->GetInput().IsKeyDown(sf::Key::Up) == true)
    {
        Rotation.x -= TurnSpeed;
    }
    if (m_pApp->GetInput().IsKeyDown(sf::Key::Down) == true)
    {
        Rotation.x += TurnSpeed;
    }
    //YAW
    if (m_pApp->GetInput().IsKeyDown(sf::Key::Left) == true)
    {
        Rotation.y -= TurnSpeed;
    }
    if (m_pApp->GetInput().IsKeyDown(sf::Key::Right) == true)
    {
        Rotation.y += TurnSpeed;
    }
    //PITCH
    if (m_pApp->GetInput().IsKeyDown(sf::Key::Q) == true)
    {
        Rotation.z -= TurnSpeed;
    }
    if (m_pApp->GetInput().IsKeyDown(sf::Key::E) == true)
    {
        Rotation.z += TurnSpeed;
    }

They are then added to m_Rotation as such:

//Rotation
m_Rotation.x += Angle.x;
m_Rotation.y += Angle.y;
m_Rotation.z += Angle.z;

(They are passed to a function internal to the thing being moved around, but nothing else is done with them).

Thoughts? Is there something else I should call to make sure all the axes being rotated around are local axes?

Upvotes: 4

Views: 12109

Answers (2)

Adam Phelps
Adam Phelps

Reputation: 479

Your problem is that you are storing your x, y, z rotations and adding to them cumulatively. Then when you render you are performing the total cumulative rotations upon the identity matrix(you are performing all rotations globally). Comment out your identity call from your render loop. And make sure you set identity at your initialize function. Then

rotate as normal
m_Rotation.x = m_Rotation.y = m_Rotation.z = 0.0f; 
//clear your rotations you don't want them to accumulate between frames
glpush
translate as normal
(all other stuff)
glpop
//you should be back to just the rotations 
//glclear and start next frame as usual

As I'm sure you found out after you accepted the original answer. The order of rotations or translations does not affect which axis the rotation occurs on, rather the point at which the rotation is performed. eg rotating a planet 15 degrees will rotate it on the global axis 15 degrees. Translating it away from origin and then rotating it will cause it to orbit the origin at the distance translated (if on the same axis as the rotation, translating on the x axis then rotating on the y axis would not have any confounding effects).

Upvotes: 1

Snickers
Snickers

Reputation: 1603

Garrick,

When you call glRotate(angle, x, y, z), it is rotating around the vector that you are passing into glRotate. The vector goes from (0,0,0) to (x,y,z).

If you want to rotate an object around the object's local axis, you need to glTranslate the object to origin, perform your rotation, and then translate it back to where it came from.

Here is an example:

//Assume your object has the following properties
sf::Vector3<float> m_rotation;
sf::Vector3<float> m_center;

//Here would be the rotate method
public void DrawRotated(sf::Vector<float> degrees) {
  //Store our current matrix 
  glPushMatrix();

  //Everything will happen in the reverse order...
  //Step 3: Translate back to where this object came from
  glTranslatef(m_center.x, m_center.y, m_center.z);

  //Step 2: Rotate this object about it's local axis
  glRotatef(degrees.y, 0, 1.0, 0);
  glRotatef(degrees.z, 0, 0, 1.0);
  glRotatef(degrees.x, 1.0, 0, 0);

  //Step 1: Translate this object to the origin
  glTranslatef(-1*m_center.x, -1*m_center.y, -1*m_center.z);

  //Render this object rotated by degrees
  Render();

  //Pop this matrix so that everything we render after this
  // is not also rotated
  glPopMatrix();
}

Upvotes: 3

Related Questions