首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于鼠标运动的旋转四元数(OpenGL和Java)

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

Stack Overflow用户
提问于 2011-10-20 21:21:01
回答 1查看 5.4K关注 0票数 5

我正在用OpenGL (具体来说是LWJGL绑定)用Java编写一个游戏。每个实体,包括相机,都有一个四元数表示它的旋转。我已经知道了如何将四元数应用到当前的OpenGL矩阵中,并且所有的东西都旋转得很好。我的问题是让相机和鼠标一起旋转。

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

代码语言:javascript
运行
复制
    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轴旋转。“旋转”是代表实体旋转的四元数。“aka”是我想要旋转四元数的数量(也就是鼠标被移动的数量)。“‘rot”是一个沿X轴的归一化向量,其值是转换为弧度的w值(我想这里的目标是给它一个角度--例如,10度--并让它沿着给定的轴旋转四元数,按这个角度旋转)。使用Quaternion.mul获取新的四元数,将其乘以旋转四元数,然后将结果存储为旋转四元数。我不知道是否有必要进行规范化,因为“rot”是正常的,而“旋转”应该已经规范化了。

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 >_<制作一些东西

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-10-20 23:09:31

代码语言:javascript
运行
复制
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));

好吧,这是完全错误的。

构造函数,它包含四个浮点数。假定它们表示一个实际的四元数。给这个构造函数的不是四元数,它是一个vec3轴和一个你期望旋转的角度。

你不能把这些推到四元数的课堂上,然后期望得到一个合法的四元数。

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

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

因此,你想要的是:

代码语言:javascript
运行
复制
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轴的旋转,你需要正确地乘以它。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7842408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档