5

我正在使用 OpenGL(具体来说是 LWJGL 绑定)用 Java 编写游戏。每个实体,包括相机,都有一个代表它的旋转的四元数。我已经想出了如何将四元数应用于当前的 OpenGL 矩阵并且一切都旋转得很好。我遇到的问题是让相机随鼠标旋转。

现在,每一帧,游戏都会抓取鼠标在一个轴上移动的量,然后将这个量应用到四元数上以进行相机旋转。这是旋转四元数的代码,我会发布它,因为我认为这是问题所在(尽管我对这类东西总是错的):

    public void rotateX(float amount){
        Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
        Quaternion.mul(rot, rotation, rotation);
        rotation.normalise();
    }

该方法应该围绕 X 轴旋转四元数。'rotation' 是代表实体旋转的四元数。“数量”是我想要旋转四元数的数量(也就是鼠标移动的数量)。'rot' 是沿 X 轴的归一化向量,其 aw 值转换为弧度(我想这里的目标是给它一个角度 - 比如 10 度 - 并让它沿着给定轴旋转四元数角度)。使用 Quaternion.mul 获取新的四元数,将其乘以旋转四元数,然后将结果存储为旋转四元数。我不知道标准化是否必要,因为“rot”是正常的,“rotation”应该已经标准化了。

rotateY 和 rotateZ 方法做同样的事情,除了改变 'rot' 的向量(y 为 0.0, 1.0, 0.0 和 z 为 0.0, 0.0, 1.0)。

当游戏开始并且相机向下看负 Z 轴时,代码似乎可以正常工作。您可以在 Y 轴上一直旋转一直围绕 X 轴旋转。但是,一旦您尝试在不向下看 Z 轴的情况下旋转相机,一切都会变得非常糟糕(我什至无法描述它,它的旋转非常奇怪)。

我的最终目标是在没有向上矢量的空间中控制一艘船。因此,当您在 Y 轴上移动鼠标时,无论船处于什么角度,它都会改变船的俯仰角(沿 X 轴旋转)。同样,当您在 X 轴上移动鼠标时,它会改变偏航角(沿 Y 轴的旋转)。我可能会以错误的方式解决这个问题,我可能只需要朝着正确的方向推动(或推动)。

如果您需要有关任何事情的更多详细信息(我的渲染是如何完成的,我正在尝试做的任何其他数学运算)只要问我就会提出来。当我使用欧拉角时,我明白了一切(这显然是 3D 应用程序开发的一大禁忌……希望有人能在我花很多时间让它们工作之前告诉我),但只要我切换到四元数,我很快就进入了我的脑海。在过去的几个月里,我一直在玩这个代码并阅读四元数试图让它工作,但我还没有真正得到任何地方:'(

非常非常令人沮丧...开始后悔尝试用 3D 制作东西>_<

4

1 回答 1

10
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));

好吧,这完全是错误的。

采用四个浮点数的构造函数假定它们代表一个实际的四元数。您给该构造函数的不是四元数;它是一个 vec3 轴和一个您希望旋转的角度。

您不能将它们推入四元数类并期望从中获得合法的四元数。

您的四元数类应该有一个构造函数或其他一些从角度和旋转轴创建四元数的方法。但是根据您链接到的文档,它没有。所以你必须自己做。

四元数不是 vec3 轴,其第四个值是角度。单位四元数表示方向的变化是一个 vec3,它是旋转轴 * 旋转角度的一半的正弦,以及一个标量分量,它是旋转角度的一半的余弦。这假设旋转角度被限制在 [-pi/2, pi/2] 范围内。

因此,你想要的是这样的:

float radHalfAngle = ... / 2.0; //See below
float sinVal = Math.Sin(radHalfAngle);
float cosVal = Math.Cos(radHalfAngle);
float xVal = 1.0f * sinVal;
float yVal = 0.0f * sinVal;  //Here for completeness.
float zVal = 0.0f * sinVal;  //Here for completeness.
Quaternion rot = new Quaternion(xVal, yVal, zVal, cosVal);

此外,amount直接转换为弧度没有意义,特别是如果amount只是鼠标移动的像素坐标增量。您需要在鼠标移动的距离和要旋转的距离之间进行某种转换比例。而且toRadians不是想要的那种规模。

还有一件事。就像您在此处所做的那样,左乘rot将围绕将执行围绕相机空间X 轴的旋转。如果你想围绕世界空间 X 轴旋转,你需要右乘它。

于 2011-10-20T23:09:31.603 回答