我正在查看一组球体,并在分别按下按钮x,y或z时围绕x,y,z旋转它们。轮换工作。但是当我用i重置我的旋转时,我并不总能得到完美的重置。
void DrawWindowOne()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 250, 250);
DrawAxis(1);
glMatrixMode(GL_MODELVIEW);
DrawSpheres();
glViewport(250, 0, 250, 250);
DrawAxis(1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
DrawSpheres();
glDisable(GL_LIGHT1);
glViewport(500, 0, 250, 250);
DrawAxis(1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_LIGHT2);
DrawSpheres();
glDisable(GL_LIGHT2);
glDisable(GL_LIGHTING);
glutSwapBuffers();
}
旋转效果很好。每个增量,我将增量添加到相应的浮点数(x \ y \ z)旋转,以存储我围绕轴进行了多少增量,然后我用它来重置回原点。
我已经发现我的问题是当我沿着2轴或更多轴旋转时。看起来好像我也只是一次只在一个轴上出现这个问题。
每个窗口都是用
绘制的{{1}}
答案 0 :(得分:1)
您可以重置矩阵调用
glLoadIdentity();
代替此代码:
glRotatef(-xRotation, 1, 0, 0);
glRotatef(-yRotation, 0, 1, 0);
glRotatef(-zRotation, 0, 0, 1);
您遇到的问题是矩阵旋转不可传递。围绕x然后y旋转与围绕y旋转然后x旋转不同。如果允许用户使用键在每个轴周围进行多个交互式增量旋转,则不可能简单地在3个变量中累积角度,并通过围绕每个变量旋转负值来撤消旋转。轴。您必须存储旋转发生的顺序以及每次旋转的次数。因此,将矩阵重置为标识要容易得多。
答案 1 :(得分:1)
samgak说回答你的问题会有什么用,但是这是值得注意的事情,并且当你的项目变得庞大而复杂时,很高兴知道如何防止陷阱。
当处理3D空间中的旋转并且需要围绕任何给定轴[X,Y,Z]旋转时,在平移旋转矩阵中使用欧拉角进行旋转,存在已知的问题。这个问题叫做万向节锁。以您的球体为例,您想要围绕任何轴旋转3D模型;在你开始旋转之前想象一下,你的球体大于一个圆圈或一个环,并且平行于每个轴。我们可以说我们的X轴环有一个指向右侧或东侧的手柄,您的Y轴环有一个指向向上或向北的手柄,而您的Z轴环指向您。当您抓住手柄并开始移动它时,该环将旋转该轴上的对象。
想象一下你的球体是地球:
X轴:当您旋转3D模型时,这将使其围绕x轴向东和向右旋转。西方和地球将与北方和地球一起转向南极和赤道改变方向。如果你向下看Z轴(LookAt),赤道会向你的方向倾斜或旋转
Y轴旋转3D模型时会使其绕着旋转 y轴北极&南方和地球将围绕两极旋转,就像在地球的日子里一样。赤道无法移动。
Z轴在旋转3D模型时会使其绕z轴旋转" LookAt" (仍然是水平但垂直于东西方),地球将围绕LookAt轴和北方和西方旋转。南极&赤道将改变方向。沿着LookAt轴向下看,你会看到波兰人和赤道人向东方和西方倾斜。
这里用类比来证明这一点,就像旋转3D模型的环的运动一样:我将使用一个电机循环,将轴的旋转视为以下
注意:当您围绕任何轴旋转对象时,环会随着显示旋转的对象移动。
现在您已经了解了每次旋转时发生的事情,我将使用Euler Angels演示Gimbal Lock。我们将单独留下Y轴,如果我们在这里使用X轴或Z轴并不重要。我将使用Z轴,因为我们向下看它,当你旋转物体时,你可以看到它左右旋转。让我们在任一方向上旋转此物体90度或PI / 2(CW,CCW)现在我们的Z轴环现在随着物体旋转,因为我们使用地球,我们仍然看到前面的相同区域我们,但赤道现在是两极,极地现在是赤道所在的地方。我们没有触及另外两个轴并且没有旋转。但是如果你注意到,你会看到Z轴环现在与X轴对齐。现在,如果我们开始围绕X轴旋转,Z轴现在正在旋转。我们失去了旋转自由的维度。这就是Gimbal Lock这个术语的用法。
如果我们重新设置所有内容,这可能会发生在3轴之间的6种不同组合中。因此,无论您使用哪种方式尝试仅使用使用欧拉角的3D数学或3D旋转矩阵在所有3维中自由旋转;哪些是使用正弦和余弦函数对每个轴进行旋转的基本矩阵,你将总是有万向锁的情况。
有一种方法可以避免这种情况!使用四元数!对它们的数学解释有点棘手,因为它是4D矢量类型,它确实涉及虚平面和复数,但是它们的编程非常容易,因为它们非常类似于矢量和矩阵。有了这个第4个组件,您可以自由旋转(X,Y,Z)而不会出现此问题。对于数学和它们的编程,Gimbal Lock和Quaternions上有很多资源,许多已经存在已经为你定义了四元数的不错的数学库,只需阅读他们关于如何应用它们的文档在你的代码中。它们让生活变得更轻松。
需要注意的一点是,在3D空间中旋转时,您不必总是使用四元数,它总是取决于需要。以下是一些使用Quaternions更好的例子,当使用Euler Angles时也没问题。
Euler Angles:如果您知道您将仅在一个轴上旋转。
四元数旋转:当你需要2轴或更多轴的自由时。
这是一个描述Gimbal Lock视频的链接,这是一个非常精确和详细的视图,可以在不到10分钟内完全理解这种现象。 YouTube: Gimbal Lock
答案 2 :(得分:0)
不要在重复调用Rotate(1,1,0,0)时在模型视图矩阵中累积旋转,而是在按下某个键时增加变量,然后使用Rotate(angle_x,1,0,0)在每次更新后设置一次单位矩阵后。否则加班会导致矩阵漂移,其中小的舍入误差将导致旋转矩阵退化。
重置对象只意味着设置angle_x = 0.0f;
另外,不要将您的lookat矩阵放在投影矩阵中,因为这会在线下方产生意外结果。有关完整说明,请参阅http://sjbaker.org/steve/omniv/projection_abuse.html。
通常在主循环之前设置一次投影矩阵。
然后每个循环将当前矩阵设置为modelview。然后,对于要绘制的每个对象,将模型视图矩阵设置为lookat * model。
我还建议阅读opengl如何使用各种矩阵here