2016-08-23 78 views
0

我想在OpenGL中制作一个可控制的球。我使用我自己的矩阵类来转换对象矩阵,但我似乎无法获得旋转权。我总是以球绕着局部轴旋转结束。 这就是它现在的样子https://gfycat.com/LongKindBassethound。长线是本地轴。围绕世界轴的旋转对象OpenGL

所以当球向前移动时,下一个侧面的移动将是错误的。即使世界在矩阵类的功能,可以让周围的任何轴旋转:

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

我觉得这个我可以把世界上方向向量,并将其转化为对象的局部空间,然后周围的结果旋转。我真的不知道该怎么做,(球*世界矢量矩阵?这是行不通的)。我真的想避免四元数,但是如果我不能这样做,我也会很欣赏这方面的建议。

编辑:更多信息

转移代码。正如你所看到的,我尝试了不同的方法,都做同样的事情...所以毫不奇怪,它不起作用。与我以前尝试尝试使用glRotatef

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

抽奖代码(显然注释掉现在)

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

请将您的驱动程序代码从您调用此函数的位置发布出来,其次,您是否有此要求来调整您自己的旋转功能?如果没有,你可以使用glRotatef() –

+0

编辑更多信息 – lega

+0

请看看这篇文章,了解OpenGL转换如何工作https://open.gl/transformations –

回答

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只是旋转积累。后乘法将确保在m_BallR累积旋转后应用新的rotation。最后翻译到m_BallT累积的最终位置。您的球将围绕其中心旋转并根据m_BallT移动。

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

+0

我编辑了我的帖子。如果我正确地理解你,我很确定我已经做好了准备。 – lega

+0

我不认为你正在这样做,从你的球中提取世界空间位置,用旋转矩阵旋转那个位置矢量,然后将球移动到新的位置。不要将复合旋转矩阵与球的矩阵相乘。 – Harish

+0

https://gfycat.com/BowedCaringArkshell这是我使用你的方法时的结果。我的目标是这样的:https://gfycat.com/LongKindBassethound适当的旋转 – lega

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向量,否则会影响将来的转换。

+0

您可以通过分别累积旋转和平移来避免矩阵求逆。它会更有效率。由于您无论如何都会覆盖平移向量,因此实际上只会反转旋转和任何比例。 – Harish

+0

@Harish在事实上不是更高效,它有很多原因是相反的......而且你不能以这种方式叠加任意转换。因为它只是'转置()',所以在b正反转矩阵上真的很容易... – Spektre

+0

@Spektre如果你做A =(A'x B)',你说它比A = B x A更有效率?我在这里错过了什么?你在第一个案子中没有积累?无论A'=转置(A)还是没有变化,你仍然在以不同的方式积累旋转。 – Harish