基于鼠标移动的旋转四元数(OpenGL和Java)

时间:2011-10-20 21:21:01

标签: java opengl lwjgl quaternions

我正在使用OpenGL编写一个Java游戏(LWJGL绑定,具体而言)。每个实体(包括相机)都有一个四元数,表示它的旋转。我已经想出如何将四元数应用于当前的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'是表示实体旋转的四元数。 'amount'是我想要旋转四元数的量(也就是鼠标移动的量)。 '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轴上一直旋转 OR 一直绕X轴旋转。但是一旦你试图旋转相机而不是向下看Z轴,一切都变得真的变得棘手(我甚至无法描述它,它旋转非常奇怪)。

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

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

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

1 个答案:

答案 0 :(得分:8)

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

好的,这是完全错误的。

constructor that takes four floats假定它们代表实际的四元数。你给那个构造函数的是而不是一个四元数;它是一个vec3轴和一个你期望旋转的角度。

你不能把它们推到四元数类中,并希望从中获得合法的四元数。

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

四元数不是vec3轴,第四个值是角度。单位四元数表示方向的变化是vec3,它是旋转轴*旋转角度的 half 的正弦,以及 half的余弦的标量分量旋转角度。这假设旋转角度被夹在[-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轴进行旋转,则需要右对齐。