围绕本地轴的OpenGL + SDL旋转
我一直在做半飞行模拟器。 我想要做的是使用俯仰滚动和偏航来旋转物体。 我已经在网上查了很多,虽然他们解释了问题所在,但我不知道如何实施解决方案。 举例来说,我的确如此:
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)
与模型视图矩阵一起使用,并且这具有相同的问题。 所以我相信它不会是灵活的lock =)。
所以在我的代码中我做到了:
float matrix[4][4];
Quat this;
this.eularToQuat(roll,pitch,yaw);
this.toMatrix(matrix);
glMultMatrix(matrix);
我想你是指万向节锁? 你说得对,每次旋转都会修改后续局部旋转发生的轴。 在你的情况下,因为OpenGL矩阵堆栈工作,所以你添加到它的每个东西都会在堆栈中的任何东西之前出现(即,它是以矩阵形式后置的乘法),从而影响偏航。
但是,即使正确实施,您的解决方案也无法解决问题。 你要做的是在本地坐标空间中获取全局y轴,这样即使在绕全局z旋转后,也可以绕全局y旋转,移动局部轴。 但是这只会给你带来很多相同的问题,如果你始终坚持使用全局坐标轴并以其他顺序应用旋转。 第二次轮换现在会干扰第一轮,而反之亦然。
另一种说服自己,你在做什么是错误的方法是看看你有多少信息。 您试图用两个数字来描述对象的方向。 两个数字不足以描述任何旋转,所以显然还有其他一些规则将两个数字转换为完整的方向。 无论您如何修改该规则,您最终都会限制您可以达到的方向。 但是对于一架飞机,你真的想要达到任何方向,所以这是一个基本的矛盾。
混淆的原因是,如果你有一个合适的方向存储方式,那么通过说'如果我通过围绕局部y旋转5,然后围绕局部z旋转10'来修改这个方向,那么完全有效。等等。问题是试图将所有这些转换合并成一对旋转。 这是不可能的。
如果你已经普遍使用OpenGL,最简单的解决方案往往是将方向存储为完整的矩阵。 通过将它们应用到矩阵中来累积俯仰和偏航旋转。 您通过glMultMatrix
将该矩阵传递给OpenGL以执行绘制。
这不是一个最佳的解决方案,但速战速决测试解决方案是使用glLoadMatrix
和glGet
通过你的矩阵加载到,然后从图形中从OpenGL的矩阵堆栈取回,分别应用转换。 这不是真正的堆栈,所以你可能会遇到一些性能问题,并且随着时间的推移,舍入误差会导致奇怪的行为,但一旦你被这种方法所说服,你就可以修复这些问题。 OpenGL手册页给出了所有变换矩阵的公式,您应该查看矩阵归一化(您可能会使用正交矩阵,无论您是否意识到这一点,这应该有助于谷歌)来处理累积舍入。
编辑:关于我在散布时发布的代码,四元数是表示方向的另一种有效方式,另一种可以安全地应用增量更新的方法。 它们也非常容易防止舍入误差。 不过,我认为你的问题可能是你没有使用四元数作为定位存储,而只是作为中间容器。 因此将它们添加到链中并不能解决您的任何问题。
编辑2:进一步的手挥手解释推动直接存储俯仰和偏航的想法还不够好:想象一下,从驾驶员的角度来看,您应用90度的偏航,然后以30度,然后偏航-90度。 然后,你最终得到的结果就好像你应用了30度的角度。 但是如果你只是存储音高和偏航,那么你就无法存储卷轴。 此外,如果您将总偏航和总音高加起来,您最终会认为您应用了30度的音高而不是一个音高。 因此,应用音高和偏航的顺序无关紧要,或者使用全局或局部坐标轴,都会得到错误的结果。
您应该使用一种转换来偏航,俯仰和滚动。 因为当你不这样做时,你会推动自己走向万向节锁。 摘抄:
万向节锁是三维空间中一个自由度的损失,当三个万向节中的两个的轴被驱动为平行配置时,“锁定”系统在退化的二维空间中旋转。
考虑一下万向座锁定飞机的这个例子:
当俯仰(绿色)和偏航(品红色)万向节对齐时,滚动(蓝色)和偏航的改变对飞机施加相同的旋转
链接地址: http://www.djcxy.com/p/95467.html