OpenGL旋转-本地轴与全局轴

4

我有一个对象,想要按照偏航角(Yaw)、俯仰角(Pitch)和横滚角(Roll)的方式旋转它,相对于该对象自己的局部坐标系而不是全局坐标系。根据这个网站上的说明,我需要按照这个顺序进行旋转。我理解为:

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);

然而,绕Y和Z轴的旋转不起作用。绕Y轴的旋转始终是相对于全局空间的,而绕Z轴的旋转仅在绕X轴的旋转为0时有效,否则会出现问题。

为了确保,我也尝试了反向顺序,但那也不起作用。我认为我已经尝试了所有其他顺序,所以问题肯定是其他方面引起的。可能是什么原因呢?

这是我获取旋转的方式:

    ///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;
    }

然后将它们添加到 m_Rotation 中:

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

它们被传递给正在移动的事物内部的一个函数,但没有其他操作。

您有什么想法吗?是否需要调用其他内容,以确保旋转的所有轴都是本地轴?


2
最好还是使用旋转矩阵。 - user406009
你尝试过以P->R->Y的顺序吗?你考虑到了一旦旋转,新旋转应用的轴是新的轴,我的意思是原始轴绕某个角度旋转后的轴吗? - Manlio
是的,我已经尝试过 P-R-Y,但这也没有帮助——Roll 仍然固定在全局轴上。我没有使用变换矩阵的经验——它们能否完全避免这种麻烦?难道我还需要三个 glRotatef() 调用并按某种顺序放置它们吗? - GarrickW
你的对象在旋转之前是否在原点..? 如果不是,你必须将其转换到原点,然后旋转并将其转换回指定位置.. 否则它会得到与你想要的不同的旋转.. - Sorceror
2个回答

3

Garrick,

当你调用glRotate(angle, x, y, z)时,它将围绕你传递给glRotate的向量旋转。该向量从(0,0,0)到(x,y,z)。

如果您想围绕对象的本地轴旋转对象,则需要将对象glTranslate到原点,执行旋转,然后将其转回到原来的位置。

这里有一个示例:

//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();
}

1
你的问题在于你正在存储你的x、y、z旋转并累加它们。然后当你渲染时,你对单位矩阵执行了所有累积旋转(即全局旋转)。请在渲染循环中注释掉你的单位调用,并确保在初始化函数中设置单位矩阵。
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

我相信您在接受原始答案后已经发现,旋转或平移的顺序不会影响旋转发生的轴,而是影响旋转执行的点。例如,将行星旋转15度将使其在全局轴上旋转15度。将其从原点平移然后旋转将导致它以平移的距离绕原点运行(如果在旋转相同的轴上,沿x轴平移然后沿y轴旋转不会产生任何混淆效应)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接