为太空模拟器/游戏旋转飞船模型

时间:2009-08-01 23:33:03

标签: c++ linux opengl 3d sdl

我现在一直在制作太空卡片。 起初我使用自己的3D引擎和软件光栅化器。

但是当实现纹理的时间到期时我放弃了。 现在我在一段时间后再次开始,现在我正在使用Opengl(使用SDL)来渲染3d模型。

但现在我又打了一堵砖墙。

我无法弄清楚如何进行适当的旋转。 作为一个空间模拟器,我想要一个类似于flighsim的控件

使用

glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleZ, 0.0f, 0.0f, 1.0f);

或类似,
如果我将模型(宇宙飞船)向左旋转90度然后向上旋转“向上”,则无法正常工作。 相反,它滚动。

这是一张说明我问题的图片。

Image Link

我尝试了几种技巧来对抗这种情况,但不知怎的,我觉得我错过了一些东西。 它几乎不可能找到模拟器样式的旋转示例。

所以我正在寻找示例,链接和旋转三维模型的理论(如宇宙飞船,飞机)。

我是否应该使用3个向量(向左,向上,向前)进行定位,因为我还需要计算诸如推进器的加速度以及随着旋转(方向?)和模型角度而变化的东西指向像火箭发动机一样的方向。

我对数学不是很好,并试图想象一个解决方案只是让人头疼

6 个答案:

答案 0 :(得分:4)

我不确定我完全理解这种情况,但听起来你可能正在描述gimbal lock。您可能希望使用quaternions来表示轮换。

答案 1 :(得分:4)

正确地做到这一点当然具有挑战性。我认为你面临的问题是你使用相同的转换矩阵进行旋转,无论“船”是如何定向的。但是你不想根据它向前转动的方式来旋转你的船,你想根据它现在面对的方式进行旋转。要做到这一点,你应该像改变你的船一样改变你的受控转弯矩阵。

例如,假设我们有三个矩阵,每个矩阵代表我们想要做的转弯。

float theta = 10.0*(pi/180.0)

matrix<float> roll = [[ cos(theta), sin(theta), 0]
                       [ -sin(theta), cos(theta), 0]
                       [ 0, 0, 1]

matrix<float> pitch = [[ cos(theta), 0, sin(theta)]
                      [ 0, 1, 0]
                      [ -sin(theta), 0, cos(theta)]

matrix<float> yaw = [[1, 0, 0]
                     [0, cos(theta), sin(theta)]
                     [0, -sin(theta), cos(theta)]]

matrix<float> orientation = [[1, 0, 0]
                            [0, 1, 0]
                            [0, 0, 1]]

每个代表三个飞行姿态轴中的每一个的10度旋转。我们还有一个用于您的船舶方向的矩阵,最初只是前进。您将通过该方向矩阵变换船舶的顶点以显示它。

然后在转弯后获得方向,你需要做一点聪明,首先将姿态控制矩阵转换为玩家的坐标,然后将其应用于方向以获得新的方向:类似

function do_roll(float amount):
    matrix<float> local_roll = amount * (roll * orientation)
    orientation = orientation * local_roll

function do_pitch(float amount):
    matrix<float> local_pitch = amount * (pitch * orientation)
    orientation = orientation * pitch_roll

function do_yaw(float amount):
    matrix<float> local_yaw = amount * (yaw * orientation)
    orientation = orientation * local_yaw

这样每次你想以某种方式旋转时,你只需要调用其中一个函数。

答案 2 :(得分:2)

这里你想要使用的是四元数。它们消除了您遇到的奇怪行为。将它们视为具有类似功能的类固醇的矩阵。通过使用允许您在特定旋转轴矢量上创建旋转矩阵的任何OpenGL功能,您可以比使用矩阵(在上面的代码中)更好地使用矩阵,但是四元数将存储您的旋转以供将来修改。例如,您从标识四元数开始并将其旋转到特定轴向量上。然后四元数被转换为对象的世界矩阵,但是您将四元数保存在对象中。下次需要执行旋转时,只需进一步修改该四元数,而不必尝试跟踪X,Y和Z轴旋转度等。

我的经验属于directx(抱歉,这里没有OpenGL体验),虽然我曾经尝试旋转在房间里弹跳的沙滩球时遇到过你的问题。他们遇到地板,墙壁和彼此时会旋转。

Google在“OpenGL Quaternion”上有很多选项,但特别是这似乎是一个很好的来源:

http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation

正如您可能已经猜到的那样,Quaternions非常适合在您的环境中处理相机。这是一个很棒的教程:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=Quaternion_Camera_Class

答案 3 :(得分:2)

你应该学习三维数学,这样你就可以更深入地了解如何控制旋转。如果您不了解该理论,则甚至难以正确复制和粘贴。特别是3D Math Primer(Amazon)等文本以及 http://gamemath.com 等相关网站将极大地帮助您完成项目(以及所有未来项目) )。

我知道您现在可能不喜欢数学,但学习相关算术将是您问题的最佳解决方案。

答案 4 :(得分:1)

四元数可能有所帮助,但更简单的解决方案可能是观察严格的旋转顺序。听起来你在y周围旋转,然后围绕x旋转。您必须始终首先旋转x,然后是y,然后是z。并不是说该命令有什么特别之处,只是如果你这样做,旋转往往会更接近你期望它们的工作方式。

编辑:为了澄清一点,你也不应该在游戏中累积轮换时间。你应该在每个框架中以身份位置开始模型,然后将x,y,然后z旋转到该框架的新位置。

答案 5 :(得分:1)

一般轮换很困难。物理学家倾向于使用一些所谓的Euler angles来描述它们。在该方法中,通过围绕固定连续的三个轴取得的三个角来描述一般旋转。但是三轴不是原始框架的X轴,Y轴和Z轴。它们通常是原始帧的Z轴,Y轴和Z轴(是的,它确实是完全一般的),或者是原始帧的两个轴,后面是中间帧中的轴。有很多选择,确保你一直遵循相同的约定可能是一个真正的麻烦。