Open GL Android 3D 对象旋转问题

发布于 2025-01-08 08:40:08 字数 595 浏览 4 评论 0原文

我在 OpenGL 中旋转 3D 对象时遇到问题。我通过加载标识(glLoadIdentity())来启动每个绘制框架,然后根据我的需要(对于相机等)在堆栈上推送和弹出。然后我希望 3D 对象能够滚动、俯仰和偏航,然后正确显示它们。

问题是……我希望能够像驾驶飞机一样进行增量旋转。因此,每次按下向上按钮时,对象都会围绕其自己的 x 轴旋转。但是,如果对象向下倾斜并选择偏航,则旋转应该围绕对象的向上向量而不是 Y 轴。

我尝试执行以下操作:

glRotatef(pitchTotal, 1,0,0);
glRotatef(yawTotal, 0,1,0);
glRotate(rollTotal, 0,0,1);

这些似乎不起作用。 (请记住向量正在正确计算)
我也尝试过...

glRotatef(pitchTotal, 1,0,0);
glRotatef(yawTotal, 0,1,0);
glRotate(rollTotal, 0,0,1);

但我仍然遇到奇怪的旋转。

长话短说...在 Open GL 中使用对象的外观、向右和向上矢量旋转 3D 对象的正确方法是什么?

I am having trouble rotating my 3D objects in Open GL. I start each draw frame by loading the identity (glLoadIdentity()) and then I push and pop on the stack according to what I need (for the camera, etc). I then want 3D objects to be able to roll, pitch and yaw and then have them displayed correctly.

Here is the catch... I want to be able to do incremental rotations as if I was flying an airplane. So every time the up button is pushed the object rotates around it's own x axis. But then if the object is pitched down and chooses to yaw, the rotation should then be around the object's up vector and not the Y axis.

I've tried doing the following:

glRotatef(pitchTotal, 1,0,0);
glRotatef(yawTotal, 0,1,0);
glRotate(rollTotal, 0,0,1);


and those don't seem to work. (Keeping in mind that the vectors are being computed correctly)
I've also tried...


glRotatef(pitchTotal, 1,0,0);
glRotatef(yawTotal, 0,1,0);
glRotate(rollTotal, 0,0,1);

and I still get weird rotations.

Long story short... What is the proper way to rotate a 3D object in Open GL using the object's look, right and up vector?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枯寂 2025-01-15 08:40:08

在进行俯仰旋转之前,您需要围绕(绕 Y)进行偏航旋转。否则,球场将关闭。

例如,您有 45 度的向下俯仰和 180 度的偏航。通过先进行俯仰,然后绕飞机的 Y 向量旋转偏航,尽管俯仰向下,但飞机最终会指向上方和向后。首先进行偏航,飞机指向向后,然后飞机 X 向量周围的俯仰将使其正确指向下方。

同样的逻辑也适用于滚动,需要最后应用。

所以你的代码应该是:

glRotatef(yawTotal, 0,1,0);
glRotatef(pitchTotal, 1,0,0);
glRotatef(rollTotal, 0,0,1);

You need to do the yaw rotation around (around Y) before you do the pitch one. Otherwise, the pitch will be off.

E.g. you have a 45 degrees downward pitch and a 180 degrees yaw. By doing the pitch first, and then rotate the yaw around the airplane's Y vector, the airplane would end up pointing up and backwards despite the pitch being downwards. By doing the yaw first, the plane points backwards, then the pitch around the plane's X vector will make it point downwards correctly.

The same logic applies for roll, which needs to be applied last.

So your code should be :

glRotatef(yawTotal, 0,1,0);
glRotatef(pitchTotal, 1,0,0);
glRotatef(rollTotal, 0,0,1);
倾城月光淡如水﹏ 2025-01-15 08:40:08

累积旋转将受到万向节锁定的影响。这样看:假设你在一架飞机上,水平飞行。您逆时针应用 90 度偏航。然后顺时针旋转 90 度。然后顺时针应用 90 度偏航。

您的飞机现在笔直向下 - 总效果是顺时针倾斜 90 度。但是,如果您只是尝试将不同的旋转相加,那么您最终会得到 90 度的滚动,并且没有任何俯仰,因为您从未对平面应用俯仰。

尝试将旋转存储和更新为三个单独的角度是行不通的。

常见的解决方案是使用四元数或将物体方向直接存储为矩阵。矩阵解决方案更容易构建,因为您可以使用 OpenGL 的内置矩阵堆栈对其进行原型设计。大多数人似乎还发现矩阵比四元数更容易理解。

因此,假设您想要使用矩阵,您的原型可能会执行以下操作(请原谅我缺乏像样的 Java 知识;我本质上将编写 C):

GLfloat myOrientation[16];

// to draw the object:
glMultMatrixf(myOrientation);
/* drawing here */

// to apply roll, assuming the modelview stack is active:
glPushMatrix();                    // backup what's already on the stack
    glLoadIdentity();              // start with the identity
    glRotatef(angle, 0, 0, 1);
    glMultMatrixf(myOrientation);  // premultiply the current orientation by the roll

    // update our record of orientation
    glGetFloatv(GL_MODELVIEW_MATRIX, myOrientation);
glPopMatrix();

您可能不想在交付代码中使用 OpenGL 堆栈,因为它并不是真正为这种用途而设计的,因此性能可能不稳定。但您可以进行原型设计和分析,而不是做出假设。您还需要考虑浮点精度问题 - 实际上您应该应用一个步骤来确保 myOrientation 在调整后仍然是正交的。

检查 Google 可能是最简单的方法,但简单来说,您将使用点积来消除从两个轴到第三个轴的错误串扰,然后从第二个轴中删除前两个轴之一,然后重新规范化所有三个轴。

Cumulative rotations will suffer from gimbal lock. Look at it this way: suppose you are in an aeroplane, flying level. You apply a yaw of 90 degrees anticlockwise. You then apply a roll of 90 degrees clockwise. You then apply a yaw of 90 degrees clockwise.

Your plane is now pointing straight downward — the total effect is a pitch of 90 degrees clockwise. But if you just tried to add up the different rotations then you'd end up with a roll of 90 degrees, and no pitch whatsoever because you at no point applied pitch to the plane.

Trying to store and update rotation as three separate angles doesn't work.

Common cited solutions are to use a quaternion or to store the object orientation directly as a matrix. The matrix solution is easier to build because you can prototype it with OpenGL's built-in matrix stacks. Most people also seem to find matrices easier to understand than quaternions.

So, assuming you want to go matrix, your prototype might do something like (please forgive my lack of decent Java knowledge; I'm going to write C essentially):

GLfloat myOrientation[16];

// to draw the object:
glMultMatrixf(myOrientation);
/* drawing here */

// to apply roll, assuming the modelview stack is active:
glPushMatrix();                    // backup what's already on the stack
    glLoadIdentity();              // start with the identity
    glRotatef(angle, 0, 0, 1);
    glMultMatrixf(myOrientation);  // premultiply the current orientation by the roll

    // update our record of orientation
    glGetFloatv(GL_MODELVIEW_MATRIX, myOrientation);
glPopMatrix();

You possibly don't want to use the OpenGL stack in shipping code because it's not really built for this sort of use and so performance may be iffy. But you can prototype and profile rather than making an assumption. You also need to consider floating point precision problems — really you should be applying a step that ensures myOrientation is still orthonormal after it has been adjusted.

It's probably easiest to check Google for that, but briefly speaking you'll use the dot product to remove erroneous crosstalk from two of the axes to the third, then to remove from one of the first two axes from the second, then renormalise all three.

守不住的情 2025-01-15 08:40:08

感谢您的回复。第一个回应为我指明了正确的方向,第二个回应也有一点帮助,但最终归结为两者的结合。最初,您的 3D 对象应该有一个成员变量,它是一个大小为 16.[0-15] 的浮点数组。然后您必须将其初始化为单位矩阵。然后,3D 对象的成员方法(如“yawObject(float amount)”)只知道您是从“对象的角度”而不是世界角度偏转对象,这将允许增量旋转。在 yawObject 方法(或俯仰、滚动对象)内,您需要调用 Matrix.rotateM(myfloatarray,0,angle,0,1,0)。这将存储新的旋转矩阵(如第一个响应中所述)。然后,当您要绘制对象时,可以使用 gl.glMultMatrix 将模型矩阵乘以 myfloatarray 矩阵。

祝你好运,如果您需要更多信息,请告诉我。

Thanks for the responses. The first response pointed me in the right direction, the second response helped a little too, but ultimately it boiled down to a combination of both. Initially, your 3D object should have a member variable which is a float array size 16. [0-15]. You then have to initialize it to the identity matrix. Then the member methods of your 3D object like "yawObject(float amount)" just know that you are yawing the object from "the objects point of view" and not the world, which would allow the incremental rotation. Inside the yawObject method (or pitch,roll ojbect) you need to call the Matrix.rotateM(myfloatarray,0,angle,0,1,0). That will store the new rotation matrix (as describe in the first response). You can then when you are about to draw your object, multiply the model matrix by the myfloatarray matrix using gl.glMultMatrix.

Good luck and let me know if you need more information than that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文