OpenGL + SDL绕局部轴旋转 [英] OpenGL + SDL rotation around local axis

查看:76
本文介绍了OpenGL + SDL绕局部轴旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究半飞行模拟器.我想做的是使用俯仰滚转和偏航旋转对象.我已经在网上看了很多东西,尽管他们解释了问题所在,但我不知道如何实施该解决方案.例如,我这样做:

I've been working on a semi flight simulator. What I am trying to do is use a pitch roll and yaw to rotate an object. I have already looked online a lot, and although they explain what the problem is I have no idea how to implement the solution. So for example I do:

glRotatef(yaw,0,1,0);
glRotatef(pitch,1,0,0);

偏航不正确,俯仰将正常工作.从我一直在阅读的内容来看,似乎对象的局部轴已更改,因此我需要找到对象的新局部轴并围绕该轴旋转.所以我尝试了类似的方法:

The yaw doesn't act properly, the pitch will work fine. And from what I have been reading it seems that the objects local axis has been changed so I need to find the object's new local axis and rotate around that. So I tried that with something like:

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);

这似乎也不起作用.

我还尝试制作一个通用的旋转矩阵,并同时给出俯仰角和偏航角,并且仍然存在相同的问题.而且我尝试使用四元数,并且仍然存在相同的问题!

I've also tried making a general rotation matrix and giving it both pitch and yaw and still the same problem. And I've tried using quaternions and the same problem still exists!

这是我的四元数代码:

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 =).

Then I converted this into a matrix and use glMultMatrix(matrix) with the modelview matrix, and this has the same problem. So I'm confident it wouldn't be gimble lock =).

所以在我的代码中,我这样做:

So in my code I do:

float matrix[4][4];
Quat this;
this.eularToQuat(roll,pitch,yaw);
this.toMatrix(matrix);
glMultMatrix(matrix);

推荐答案

我认为您是指万向节锁?没错,每次旋转都会修改将围绕其进行后续局部旋转的轴.在您的情况下,这会影响偏航,因为OpenGL矩阵堆栈可以正常工作,因此您添加到其中的每件事在概念上都在堆栈上已有的东西之前发生(即,以矩阵形式进行事后乘法).

I think you're referring to gimbal lock? You're right that each rotation modifies the axes around which subsequent local rotations will occur. In your case that affects the yaw because the OpenGL matrix stack works so that each thing you add to it occurs conceptually before whatever is already on the stack (ie, it's post multiplication in matrix terms).

但是,即使正确实施,您的解决方案也无法解决问题.您要做的是将全局y轴放置在局部坐标空间中,以便即使绕全局z旋转也可以绕全局y旋转,从而移动了局部轴.但这只会给您带来许多相同的问题,就像您始终陷入全局轴并以其他顺序应用旋转一样.现在,第二轮旋转将干扰第一轮旋转,而不是相反.

Your solution, however, won't solve the problem even if implemented correctly. What you're trying to do is get the global y axis in local coordinate space so that you can rotate around the global y even after you've rotated around the global z, shifting the local axes. But that just buys you much the same problems as if you'd stuck with global axes throughout and applied the rotations in the other order. The second rotation will now interfere with the first rather than vice versa.

让自己确信自己正在做的事情是错误的另一种方法是查看拥有的信息量.您试图用两个数字描述对象的方向.两个数字不足以描述任何旋转,因此显然存在一些其他规则可以将两个数字转换为一个完整的方向.无论您做什么修改该规则,最终都将限制您可以达到的方向.但是对于飞机,您真的希望能够达到任何方向,所以这是一个基本矛盾.

Another way to convince yourself that what you're doing is wrong is to look at how much information you have. You're trying to describe the orientation of an object with two numbers. Two numbers isn't enough to describe any rotation whatsoever, so there's obviously some other rule in there to convert two numbers into a complete orientation. Whatever you do to modify that rule, you're going to end up limiting the orientations you can reach. But with an aeroplane you really want to be able to reach any orientation, so that's a fundamental contradiction.

之所以会产生混乱,是因为如果您有一种合适的方向存储方式,那么通过说如果我通过围绕局部y旋转5,然后围绕局部z旋转来修改方向,这是什么完全正确呢? 10?'等.问题是尝试将所有这些转换汇总为一对旋转.这是不可能的.

The confusion comes because, if you have a suitable way of storing orientation, it's completely valid to work forward from that by saying 'what is the orientation if I modify that by rotating around local y by 5, then around local z by 10?', etc. The problem is trying to aggregate all those transformations into a single pair of rotations. It isn't possible.

最简单的解决方案是将方向存储为完整的矩阵,如果您通常已经使用OpenGL.通过将俯仰和偏航旋转应用于该矩阵,可以将它们累积起来.您可以通过glMultMatrix将该矩阵传递给OpenGL以执行绘图.

The easiest solution if you're already generally up on OpenGL tends to be to store the orientation as a complete matrix. You accumulate pitch and yaw rotations by applying them as they occur to that matrix. You pass that matrix to OpenGL via glMultMatrix to perform your drawing.

这不是最佳解决方案,但快速修复测试解决方案是使用glLoadMatrixglGet来应用转换,方法是将矩阵加载到OpenGL矩阵堆栈中,然后从图形中将其检索出来.堆栈并不是真正的目的,因此您可能会遇到一些性能问题,随着时间的推移,舍入错误将导致异常行为,但是一旦您相信该方法,就可以修复这些问题. OpenGL手册页提供了所有变换矩阵的公式,您应该查询矩阵归一化(无论您是否意识到,都可能使用正交矩阵,这对Google会有帮助).

It's not an optimal solution but a quick fix test solution would be to use glLoadMatrix and glGet to apply transformations by loading your matrix to and then retrieving it from the OpenGL matrix stack, separately from your drawing. It's not really what the stack is for so you'll probably get some performance problems and over time rounding errors will cause odd behaviour but you can fix those once you're persuaded by the approach. The OpenGL man pages give the formulas for all transformation matrices and you should look up matrix normalisation (you'll probably be using an orthonormal matrix whether you realise it or not, which should help with Google) to deal with cumulative rounding.

关于您在我闲逛时发布的代码,四元数是表示方向的另一种有效方法,并且是可以安全地应用增量更新的另一件事.它们也很紧凑,很容易防止舍入错误.但是,我认为您的问题可能是您没有将四元数用作定向存储,而只是将其用作中间容器.因此,将它们添加到链中并不能解决您的任何问题.

with respect to the code you've posted while I was rambling, quaternions are another valid way of representing orientation and another thing that you can apply incremental updates to safely. They're also compact very easy to protect from rounding errors. However I think your problem may be that you aren't using quaternions as the storage for orientation, merely as an intermediate container. So adding them to the chain doesn't fix any of your problems.

进一步的挥舞手法的解释来推动直接存储俯仰和偏航的想法还不够好:想象一下,从飞行员的角度来看,您应用了90度的偏航,然后倾斜30度,然后偏航-90度.然后,最终效果就好象您应用了30度的滚动一样.但是,如果您仅存储俯仰和偏航,则无法存储滚动.此外,如果仅将总偏航角和总俯仰角相加,则最终会以为您应用了30度的俯仰角而不是横滚角.因此,无论按什么顺序应用俯仰和偏航,或者使用全局轴还是局部轴,都不会得到错误的结果.

a further bit of hand-waving explanation to push the idea that directly storing pitch and yaw isn't good enough: imagine that, from the point of view of the pilot, you apply a yaw of 90 degrees, then a pitch of 30 degrees, then a yaw of -90 degrees. Then you end up exactly as if you'd applied a roll of 30 degrees. But if you're just storing pitch and yaw then you've no way of storing roll. Furthermore, if you just add up the total yaw and total pitch you end up thinking you've applied a pitch of 30 degrees rather than a roll. So it doesn't matter what order you apply pitch and yaw, or whether you use global or local axes, you get the wrong result.

这篇关于OpenGL + SDL绕局部轴旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆