2

我一直在研究太空模拟游戏。起初,我使用自己的 3d 引擎和软件光栅化器。

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

但现在我撞到了另一堵砖墙。

我不知道如何进行适当的旋转。作为一个太空模拟器,我想要与飞行模拟类似的控制

使用

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 度然后将其“向上”旋转,则无法正常工作。相反,它滚动。

这是说明我的问题的图像。

图片链接

我尝试了几种技巧来尝试解决这个问题,但不知何故我觉得我错过了一些东西。几乎不可能找到模拟器风格的旋转示例也无济于事。

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

我是否应该使用 3 个向量(左、上、前)作为方向,因为我还必须计算诸如推进器的加速度之类的东西,这些东西会随着旋转(方向?)和模型中的视角点而改变像火箭发动机一样的方向。

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

4

6 回答 6

4

我不确定我是否完全理解这种情况,但听起来你可能在描述gimbal lock。您可能想看看使用四元数来表示您的旋转。

于 2009-08-01T23:44:08.147 回答
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

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

于 2009-08-01T23:55:45.643 回答
2

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

我的经验是在 directx 中(抱歉,这里没有 OpenGL 经验),尽管当我尝试旋转在房间里弹跳的沙滩球并在遇到地板、墙壁和彼此时旋转时,我确实遇到了你的问题。

谷歌有很多关于“OpenGL 四元数”的选项,但这似乎是一个很好的来源:

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

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

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

于 2009-08-01T23:42:33.673 回答
2

您应该学习 3D 数学,以便更深入地了解如何控制旋转。如果您不了解理论,甚至很难正确复制和粘贴。特别是诸如 3D Math Primer(亚马逊)之类的文本,以及诸如http://gamemath.com之类的相关网站将极大地帮助您完成您的项目(以及所有未来的项目)。

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

于 2009-08-02T05:57:09.950 回答
1

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

编辑:澄清一点,你也不应该在游戏中随着时间累积轮换。每一帧你都应该从同一位置开始你的模型,然后旋转 x、y、z 到该帧的新位置。

于 2009-08-01T23:57:39.273 回答
1

一般轮换是困难的。物理学家倾向于使用一些所谓的欧拉角来描述它们。在该方法中,一般旋转由围绕三个轴连续固定的三个角度来描述。但三轴并不是原车架的X、Y、Z轴。它们通常是原始框架的 Z、Y 和 Z 轴(是的,它确实是完全通用的),或者来自原始框架的两个轴,然后是中间框架中的一个轴。有很多选择,确保您始终遵循相同的约定可能会很麻烦。

于 2009-08-02T04:50:57.637 回答