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

Posted

技术标签:

【中文标题】为太空模拟器/游戏旋转宇宙飞船模型【英文标题】:Rotating a spaceship model for a space simulator/game 【发布时间】:2009-08-01 23:33:03 【问题描述】:

我从事太空模拟工作已有一段时间了。 起初我使用的是我自己的 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 度然后将其“向上”旋转,则无法正常工作。 相反,它会滚动。

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

Image Link

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

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

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

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

【问题讨论】:

我终于破解了!我使用描述模型方向的矩阵。当我按下向上键时,会调用一个函数来创建一个旋转矩阵,我围绕 x 旋转所需的量,然后将其乘以模型方向矩阵。 【参考方案1】:

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

【讨论】:

我之前一直在尝试四元数,但又试了一次。好吧,它似乎使旋转更正确,但是现在当我旋转它时,盒子有点扭曲了。【参考方案2】:

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

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

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

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

【讨论】:

【参考方案3】:

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

我的经验是在 directx 中(抱歉,这里没有 OpenGL 经验),虽然我曾经遇到过你的问题,当时我试图旋转在房间里弹跳的沙滩球并在遇到地板、墙壁和彼此时旋转.

Google 有很多关于“OpenGL Quaternion”的选项,但是这似乎是一个很好的来源:

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

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

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

我已经有了 3D Math Primer,它在我开始的时候帮助很大。是不是有时我读过它,似乎我需要再读一遍。【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

【讨论】:

以上是关于为太空模拟器/游戏旋转宇宙飞船模型的主要内容,如果未能解决你的问题,请参考以下文章

玩·《Universe Sandbox》让你利用上帝视角创造宇宙!

《宇宙沙盘2/Universe Sandbox2》即将提供VR支持:“抓来那个月球扔向地球去”

[OpenJudge] 宇航员(模拟)

有啥好玩的飞机游戏

Steam《星际乐土太空基地》预购开启 售价188元

Swift Spritekit 应用旋转脉冲