繁体   English   中英

围绕局部轴的OpenGL + SDL旋转

[英]OpenGL + SDL rotation around local axis

我一直在研究半飞行模拟器。 我想要做的是使用俯仰滚动和偏航来旋转物体。 我已经在网上看了很多,虽然他们解释了问题所在但我不知道如何实现解决方案。 所以我举例说:

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)和modelview矩阵,这也有同样的问题。 所以我相信它不会是gimble 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来执行绘图。

这不是一个最佳的解决方案,但速战速决测试解决方案是使用glLoadMatrixglGet通过你的矩阵加载到,然后从图形中从OpenGL的矩阵堆栈取回,分别应用转换。 这不是堆栈的真正含义所以你可能会遇到一些性能问题,而且随着时间的推移舍入错误会导致奇怪的行为,但是一旦你被这种方法说服,你就可以修复它们。 OpenGL手册页给出了所有变换矩阵的公式,你应该查找矩阵归一化(你可能会使用正交矩阵,无论你是否意识到,这应该有助于谷歌)来处理累积舍入。

编辑:对于你在漫游时发布的代码,四元数是表示方向的另一种有效方式,另一种可以安全地应用增量更新的方法。 它们也很紧凑,非常容易防止圆角误差。 但是我认为你的问题可能是你没有使用四元数作为方向的存储,只是作为一个中间容器。 因此,将它们添加到链中并不能解决您的任何问题。

EDIT2:另外一个挥手的解释,推动直接存储俯仰和偏航的想法不够好:想象一下,从飞行员的角度来看,你应用90度的偏航,然后是30度,然后偏航-90度。 然后你最终就像你应用了30度的卷一样。 但是,如果你只是存储音高和偏航,那么你就无法存储音量。 此外,如果你只是将总的偏航和总音高相加,你最终会认为你应用了30度而不是滚动的音高。 因此,无论您使用俯仰和偏航的顺序是什么,或者您使用全局轴还是局部轴,都会得到错误的结果。

你应该使用一个变换进行偏航,俯仰和滚动。 因为当你不这样做时,你会把自己推向万向节锁 摘抄:

万向节锁定是三维空间中一个自由度的损失,当三个万向节中的两个的轴被驱动成平行配置时,“锁定”系统在退化的二维空间中旋转。

考虑这个Gimbal锁定飞机的例子:

万向节锁定的飞机

当俯仰(绿色)和偏航(洋红色)万向节变得对齐时,滚动(蓝色)和偏航的变化对飞机施加相同的旋转

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM