现在,每一帧,游戏都会抓取鼠标在一个轴上移动的数量,然后将该数量应用到四元数以便相机旋转.这是旋转四元数的代码,我会发布它,因为我认为这就是问题所在(尽管我对这类东西总是错的):
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轴上一直旋转或一直围绕X轴旋转.但是一旦你试图旋转相机而不是俯视Z轴,一切都变得非常棘手(我甚至无法描述它,它旋转非常奇怪).
我的最终目标是在没有向上矢量的空间中控制船只.因此,当您在Y轴上移动鼠标时,无论船舶处于什么角度,它都会改变船的俯仰角(沿X轴旋转).类似地,当您在X轴上移动鼠标时,它会改变偏航(沿Y轴旋转).我可能会以错误的方式解决这个问题,我可能只需要向正确的方向推(或推).
如果你需要更多关于任何事情的细节(我的渲染是如何完成的,我正在尝试做的任何其他数学)只是问,我会把它提出来.当我使用欧拉角时,我明白了一切(显然这对于3D应用程序开发来说是一个很大的禁忌…希望有人会告诉我,在我沉没了大量时间让他们去工作之前)但是我一见到切换到四元数,我很快就进入了我的头脑.过去几个月我一直在玩这个代码并阅读四元数试图让它工作,但我还没有真正得到任何东西:'(
非常非常令人沮丧……开始后悔尝试在3D中制作东西> _<
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
好的,这是完全错误的.
constructor that takes four floats假定它们代表实际的四元数.你给的那个构造函数不是四元数;它是一个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);
此外,直接将数量转换为弧度也没有意义,特别是如果数量只是鼠标移动的像素坐标增量.在鼠标移动的距离和想要旋转的距离之间需要某种转换比例.而对于拉丁人来说,并不是你想要的那种规模.
还有一件事.如此处左旋乘,将围绕摄像机空间X轴执行旋转.如果要围绕世界空间X轴进行旋转,则需要右对齐.