围绕World Axis OpenGL旋转对象

时间:2016-08-23 13:09:52

标签: c++ opengl matrix vector

我正在尝试在OpenGL中制作一个可控制的球。我正在使用自己的矩阵类来转换对象矩阵,但我似乎无法使Rotation正确。我总是围绕局部轴旋转球。 这就是它现在的样子https://gfycat.com/LongKindBassethound。长线是局部轴。

因此,当球向前移动时,下一个侧移将是错误的。矩阵类中的函数允许围绕任何轴旋转:

Matrix& Matrix::rotationAxis(const Vector& Axis, float Angle) {
const float Si = sin(Angle);
const float Co = cos(Angle);
const float OMCo = 1 - Co;
Vector Ax = Axis;
Ax.normalize();

m00= (Ax.X * Ax.X) * OMCo + Co;
m01= (Ax.X * Ax.Y) * OMCo - (Ax.Z * Si);
m02= (Ax.X * Ax.Z) * OMCo + (Ax.Y * Si);
m03= 0;

m10= (Ax.Y * Ax.X) * OMCo + (Ax.Z * Si);
m11= (Ax.Y * Ax.Y) * OMCo + Co;
m12= (Ax.Y * Ax.Z) * OMCo - (Ax.X * Si);
m13= 0;

m20= (Ax.Z * Ax.X) * OMCo - (Ax.Y * Si);
m21= (Ax.Z * Ax.Y) * OMCo + (Ax.X * Si);
m22= (Ax.Z * Ax.Z) * OMCo + Co;
m23= 0;

m30= 0;
m31= 0;
m32= 0;
m33= 1;

return *this;
}

我认为我可以使用世界方向向量并将它们转换为对象的局部空间,然后围绕结果旋转。我真的不知道如何做到这一点(球*世界矢量的矩阵?这不起作用)。我真的想避免四元数,但如果我不能这样做,我也会很感激那方面的建议。

编辑:更多信息

transforamtion Code。正如你所看到的,我尝试了不同的方法,所有方法都是一样的......所以毫不奇怪,它不起作用。

Matrix transM, rotX, rotZ;
rotationX = straight;
rotationZ = side;
if (velocity != Vector(0, 0, 0)) {
    velocity.X = -0.0005 * DeltaTime;
    velocity.X = clamp(velocity.X, 0, FLT_MAX);

    velocity.Z = -0.0005 * DeltaTime;
    velocity.Z = clamp(velocity.Z, 0, FLT_MAX);
}

velocity.X += speed * -side * DeltaTime;
velocity.Z += speed * straight * DeltaTime;
transM.translation(velocity.X, 0, velocity.Z);

if (velocity.Z != 0 || velocity.X != 0) {
    //http://mathworld.wolfram.com/EulerAngles.html
    //http://gamedev.stackexchange.com/questions/67199/how-to-rotate-an-object-around-world-aligned-axes

    Vector localAxisX =  m_Ball * Vector(1, 0, 0);
    Vector localAxisZ = m_Ball * Vector(0, 0, 1);
    rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime);
    rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime);
    //rotX.rotationX(0.5* M_PI * straight * DeltaTime * 3);
    //rotZ.rotationZ(0.5* M_PI * side * DeltaTime * 3);
    //Matrix fullRotation.rotationYawPitchRoll(Vector(0,  0.5* M_PI * straight * DeltaTime, 0.5* M_PI * side * DeltaTime));
    m_Ball = transM * m_Ball * (rotX*rotZ);
}
else {
    m_Ball = transM * m_Ball;
}

使用我之前尝试使用glRotatef(显然现在已注释掉)来绘制代码

void Ball::draw(float DeltaTime) {
  glPushMatrix();
  glMultMatrixf(m_Ball);
  if(rotationX)
    glRotatef(0.5* M_PI * rotationX * DeltaTime, 1.0, 0.0, 0.0);
  if(rotationZ)
    glRotatef(0.5* M_PI * rotationZ * DeltaTime, 0.0, 0.0, 1.0);
  g_Model_ball.drawTriangles();
  glPopMatrix();
  drawAxis();
}

2 个答案:

答案 0 :(得分:1)

我强烈建议使用四元数来轻松处理复合旋转并避免万向节锁定。

https://en.wikipedia.org/wiki/Gimbal_lock

关于你的评论和视频,你想绕着球的中心旋转。看来你在m_Ball累积你的轮换,但做了一个奇怪的transM乘法。您也可能在transM累积翻译。

尽量不要混合您的翻译和轮播,并避免在m_Ball中累积它们。你可以这样做。

//transformation matrix
transM.translation(velocity.X, 0, velocity.Z);

//accumulate translations in m_BallT
m_BallT = transM * m_BallT;

//final Rotation
Matrix rotation = rotX * rotZ;

//accumulate rotations in m_BallR
m_BallR = rotation * m_BallR;

//now compute your final transformation matrix from accumulated rotations and translation
m_Ball = m_BallT * m_BallR;

注意m_BallR如何累积轮换。后乘法将确保在rotation中累积轮换后应用新的m_BallR。最后转换为m_BallT中累积的最终位置。您的球将围绕其中心旋转并根据m_BallT移动。

您也可以简单地替换m_BallR上的转换组件,以避免额外的矩阵乘法。

答案 1 :(得分:0)

Vector newPos(m_Ball.translation().X + velocity.X, terrainNoise.GetHeight(m_Ball.translation().X, m_Ball.translation().Z) + 0.5, m_Ball.translation().Z + velocity.Z);

rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime * abs(velocity.Z) * 100);
rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime * abs(velocity.X) * 100);

m_Rotation = (rotX*rotZ);

m_Ball = (m_Ball.invert() * m_Rotation).invert();


m_Ball.m03 = newPos.X;
m_Ball.m13 = newPos.Y;
m_Ball.m23 = newPos.Z;

这是我在阅读@Spektre提供的this链接后想出的解决方案。基本上你只需要反转球的ModelMatrix,使其进入世界位置,进行旋转然后将其转换回局部空间。

您必须在旋转之前设置newPos Vector,否则会影响将来的转换。