我一直在研究半飞行模拟器。我想要做的是使用俯仰滚动和偏航来旋转物体。我已经在网上看了很多,虽然他们解释了问题所在但我不知道如何实现解决方案。例如,我这样做:
glRotatef(yaw,0,1,0);
glRotatef(pitch,1,0,0);
偏航不能正常发挥,音高可以正常工作。从我一直在阅读的内容看来,对象局部轴已被改变,所以我需要找到对象的新局部轴并围绕它旋转。所以我尝试了类似的东西:
newpitch=pitch/57.29
VectorA(0,cos(newpitch)-sin(newpitch),sin(newpitch)+cos(newpitch));
glRotatef(yaw,vec.getXAxis(),vec.getYAxis(),vec.getZAxis());
glRotatef(pitch,1,0,0);
这似乎也无效。
我也试过制作一般的旋转矩阵并给它提供俯仰和偏航,但仍然存在同样的问题。我尝试过使用四元数,同样的问题仍然存在!
这是我的四元数代码:
void Quat::eulerToQuat(float roll,float pitch,float yaw){
float radiansY = yaw/57.2;
float radiansZ = roll/57.2;
float radiansX = pitch/57.2;
float sY = sinf(radiansY * 0.5);
float cY = cosf(radiansY * 0.5);
float sZ = sinf(radiansZ * 0.5);
float cZ = cosf(radiansZ * 0.5);
float sX = sinf(radiansX * 0.5);
float cX = cosf(radiansX * 0.5);
w = cY * cZ * cX - sY * sZ * sX;
x = sY * sZ * cX + cY * cZ * sX;
y = sY * cZ * cX + cY * sZ * sX;
z = cY * sZ * cX - sY * cZ * sX;
}
然后我将其转换为矩阵并将glMultMatrix(matrix)
与模型视图矩阵一起使用,这也存在同样的问题。所以我相信它不会是gimble lock =)。
所以在我的代码中我做了:
float matrix[4][4];
Quat this;
this.eularToQuat(roll,pitch,yaw);
this.toMatrix(matrix);
glMultMatrix(matrix);
答案 0 :(得分:3)
我认为你指的是万向节锁?你是对的,每个旋转都会修改后续局部旋转的轴。在你的情况下影响偏航,因为OpenGL矩阵堆栈的工作原理使你添加到它的每一个东西在概念上发生在堆栈中已有的东西之前(即,它是以矩阵术语的后乘法)。
但是,即使正确实施,您的解决方案也无法解决问题。您要做的是在局部坐标空间中获取全局y轴,以便即使在围绕全局z旋转,移动局部轴之后也可以围绕全局y旋转。但这只会给你带来很多相同的问题,就好像你一直坚持使用全局轴并以其他顺序应用旋转一样。第二次旋转现在将干扰第一次旋转而不是反之亦然。
另一种让自己相信你正在做的事情是错误的方法是看看你有多少信息。您试图用两个数字描述对象的方向。两个数字不足以描述任何旋转,因此显然有一些其他规则将两个数字转换为完整的方向。无论您如何修改该规则,您最终都会限制您可以达到的方向。但是有了飞机,你真的希望能够达到任何方向,这是一个基本的矛盾。
之所以产生混淆,是因为,如果你有一个合适的存储方向的方法,那么通过说“如果我通过绕局部y旋转5,然后绕着局部z到那里来修改它的方向是什么,那么向前工作是完全有效的”。 10?'等问题是试图将所有这些转换聚合成一对旋转。这是不可能的。
如果您已经普遍使用OpenGL,最简单的解决方案往往是将方向存储为完整的矩阵。通过在该矩阵中出现它们时应用它们来累积俯仰和偏航旋转。您可以通过glMultMatrix
将该矩阵传递给OpenGL来执行绘图。
这不是最佳解决方案,但快速修复测试解决方案是使用glLoadMatrix
和glGet
通过将矩阵加载到OpenGL矩阵堆栈然后从OpenGL矩阵堆栈中检索来应用转换。画画。这不是堆栈的真正含义所以你可能会遇到一些性能问题,而且随着时间的推移舍入错误会导致奇怪的行为,但是一旦你被这种方法说服,你就可以修复它们。 OpenGL手册页给出了所有变换矩阵的公式,你应该查找矩阵归一化(你可能会使用正交矩阵,无论你是否意识到,这应该有助于谷歌)来处理累积舍入。
编辑:关于你在漫游时发布的代码,四元数是另一种表示方向的有效方式,另一种是你可以安全地应用增量更新。它们也很紧凑,非常容易防止圆角误差。但是我认为你的问题可能是你没有使用四元数作为方向的存储,只是作为一个中间容器。因此,将它们添加到链中并不能解决您的任何问题。
EDIT2:进一步的挥手解释推动直接存储俯仰和偏航的想法不够好:想象一下,从飞行员的角度来看,你应用90度的偏航,然后间距为30度,然后偏航为-90度。然后你最终就像你应用了30度的卷一样。但是,如果你只是存储音高和偏航,那么你就无法存储音量。此外,如果你只是将总的偏航和总音高相加,你最终会认为你应用了30度而不是滚动的音高。因此,无论您使用俯仰和偏航的顺序是什么,或者使用全局轴还是局部轴,都会得到错误的结果。
答案 1 :(得分:1)
你应该使用一个变换进行偏航,俯仰和滚动。因为当你不这样做时,你会把自己推向gimbal lock。摘录:
万向锁是一种自由度的丧失 当三个轴中的两个轴发生时产生的三维空间 万向节被驱动成并联配置,“锁定”系统 在退化的二维空间中旋转。
考虑这个Gimbal锁定飞机的例子:
当球场(绿色)和偏航(洋红色) 万向节变得对齐,滚动变化(蓝色)和偏航应用相同 旋转到飞机