【问题标题】:Rotating quaternions based on mouse movement (OpenGL and Java)基于鼠标移动的旋转四元数(OpenGL 和 Java)
【发布时间】:2011-10-20 21:21:01
【问题描述】:

我正在使用 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 制作东西>_

【问题讨论】:

  • 你想绕 X 轴旋转。 哪个 X轴?世界空间?相机空间?

标签: java opengl lwjgl quaternions


【解决方案1】:
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));

好吧,这完全是错误的。

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

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

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

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

【讨论】:

  • 我实际上使用的是Quaternion class included with LWJGL。在那条线上创建的四元数仅用于与当前旋转四元数相乘,它不用于其他任何地方。所以基本上它是在创建一个仅在 x 轴上以角度 w 移动的四元数,然后将其乘以当前旋转。
  • 非常感谢您的帮助!像魅力一样工作!你为我清理了很多东西。虽然我最终在数量上使用了 toRadians,因为数量被传递给旋转方法作为在该轴上旋转的角度(鼠标增量的缩放在传递给方法之前完成 - 可能应该将“数量”更改为“角度”:P)
  • 顺便说一下,可以设置四元数从轴角度来完成所有这些 B.S.为你。请注意!
猜你喜欢
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
  • 2021-04-12
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多