如何使用 glRotatef() 和 glTranslatef() 在 3D 世界中增量移动

发布于 2024-10-02 18:34:46 字数 1442 浏览 1 评论 0原文

我有一些在 3D 空间中用 OpenGL 渲染的 3D 模型,并且在旋转移动“角色”(即相机)时遇到了一些麻烦以及这个世界内部的翻译。

我从一些外部事件(用户输入的图像或来自 GPS+罗盘设备的一些数据)接收输入(即移动的坐标/转动的坐标),并且事件类型是旋转或者翻译

我编写了这个方法来管理这些事件:

- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{

    [super startDrawingFrame];
    if (degrees != 0)
    {
        glRotatef(degrees, 0, 0, 1);
    }

    if (translatedLat != 0)
    {
        glTranslatef(translatedLat, -translatedLong, 0);
    }

   [self redrawView];
}

然后在 redrawView 中我实际上正在绘制场景和我的模型。它是这样的:

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

NSInteger nModels = [models count];

for (NSInteger i = 0; i < nModels; i++) 
{
    MD2Object * mdobj = [models objectAtIndex:i];
    glPushMatrix();
    double * deltas = calloc(sizeof(double),2);

    deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
    deltas[1] = currentCoords[1] - mdobj.modelPosition[1];

    glTranslatef(deltas[0], -deltas[1], 0);

    free(deltas);
    [mdobj setupForRenderGL];
    [mdobj renderGL];   
    [mdobj cleanupAfterRenderGL];
    glPopMatrix();

}
[super drawView];

问题是,当平移时,旋转事件被一个接一个地调用:例如,当我增量旋转一些迭代时(仍然围绕原点),然后我平移并最终再次旋转,但看起来最后一次旋转不是围绕当前(平移)位置发生的,而是围绕旧位置(旧原点)发生的。我很清楚,当变换的顺序颠倒时,就会发生这种情况,但我相信,在绘图之后,翻译系统会给出新的世界中心。

我缺少什么?我该如何解决这个问题? (任何对 OpenGL 的引用也将受到赞赏)

I have some 3D models that I render in OpenGL in a 3D space, and I'm experiencing some headaches in moving the 'character' (that is the camera) with rotations and translation inside this world.

I receive the input (ie the coordinates where to move/the dregrees to turn) from some extern event (image a user input or some data from a GPS+compass device) and the kind of event is rotation OR translation .

I've wrote this method to manage these events:

- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{

    [super startDrawingFrame];
    if (degrees != 0)
    {
        glRotatef(degrees, 0, 0, 1);
    }

    if (translatedLat != 0)
    {
        glTranslatef(translatedLat, -translatedLong, 0);
    }

   [self redrawView];
}

Then in redrawView I'm actualy drawing the scene and my models. It is something like:

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

NSInteger nModels = [models count];

for (NSInteger i = 0; i < nModels; i++) 
{
    MD2Object * mdobj = [models objectAtIndex:i];
    glPushMatrix();
    double * deltas = calloc(sizeof(double),2);

    deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
    deltas[1] = currentCoords[1] - mdobj.modelPosition[1];

    glTranslatef(deltas[0], -deltas[1], 0);

    free(deltas);
    [mdobj setupForRenderGL];
    [mdobj renderGL];   
    [mdobj cleanupAfterRenderGL];
    glPopMatrix();

}
[super drawView];

The problem is that when translation an rotation events are called one after the other: for example when I'm rotating incrementally for some iterations (still around the origin) then I translate and finally rotate again but it appears that the last rotation does not occur around the current (translated) position but around the old one (the old origin). I'm well aware that this happens when the order of transformations is inverted, but I believed that after a drawing the new center of the world was given by the translated system.

What am I missing? How can I fix this? (any reference to OpenGL will be appreciated too)

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

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

发布评论

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

评论(2

濫情▎り 2024-10-09 18:34:46

我建议不要在事件处理程序中进行累积转换,而是在内部存储转换的当前值,然后仅转换一次,但我不知道这是否是您想要的行为。

伪代码:

someEvent(lat, long, deg)
{
  currentLat += lat;
  currentLong += long;
  currentDeg += deg;
}

redraw()
{
  glClear()
  glRotatef(currentDeg, 0, 0, 1);
  glTranslatef(currentLat, -currentLong, 0);
  ... // draw stuff
}

I would recommend not doing cummulative transformations in the event handler, but internally storing the current values for your transformation and then only transforming once, but I don't know if this is the behaviour that you want.

Pseudocode:

someEvent(lat, long, deg)
{
  currentLat += lat;
  currentLong += long;
  currentDeg += deg;
}

redraw()
{
  glClear()
  glRotatef(currentDeg, 0, 0, 1);
  glTranslatef(currentLat, -currentLong, 0);
  ... // draw stuff
}
谁对谁错谁最难过 2024-10-09 18:34:46

听起来这里发生了几件事:

首先,您需要意识到旋转是围绕原点发生的。因此,当您平移然后旋转时,您并不是围绕您认为的原点旋转,而是围绕新原点旋转,即 T-10(通过平移逆向变换的原点)。

其次,你让事情变得比你真正需要的要困难得多。您可能需要考虑使用 gluLookAt。本质上,您给它在场景中的一个位置和场景中要查看的点以及一个“向上”向量,它将正确设置场景。要正确使用它,请跟踪相机所在的位置,将该矢量称为p,并将矢量n(对于正常情况...表示您正在寻找的方向) 和 u (你的向上向量)。如果 nu 是正交向量(即它们彼此正交并且具有单位长度),则更容易实现更高级的功能。如果这样做,您可以计算 r = n x u(您的“右”向量),这将是一个法向量正交给另外两个。然后,您“查看”p+n 并提供 u 作为向上向量。

理想情况下,您的 nur 具有某种规范形式,例如:

n = <0, 0, 1>
u = <0, 1, 0>
r = <1, 0, 0>

然后,您逐渐累积旋转并将它们应用到方向向量的规范中。您可以使用欧拉旋转四元数旋转 来累积您的旋转(我非常欣赏各种原因)。

It sounds like you have a couple of things that are happening here:

The first is that you need to be aware that rotations occur about the origin. So when you translate then rotate, you are not rotating about what you think is the origin, but the new origin which is T-10 (the origin transformed by the inverse of your translation).

Second, you're making things quite a bit harder than you really need. What you might want to consider instead is to use gluLookAt. You essentially give it a position within your scene and a point in your scene to look at and an 'up' vector and it will set up the scene properly. To use it properly, keep track of where you camera is located, call that vector p, and a vector n (for normal ... indicates the direction you're looking) and u (your up vector). It will make things easier for more advanced features if n and u are orthonormal vectors (i.e. they are orthoginal to each other and have unit length). If you do this, you can compute r = n x u, (your 'right' vector), which will be a normal vector orthoginal to the other two. You then 'look at' p+n and provide the u as the up vector.

Ideally, your n, u and r have some canonical form, for instance:

n = <0, 0, 1>
u = <0, 1, 0>
r = <1, 0, 0>

You then incrementally accumulate your rotations and apply them to the canonical for of your oritentation vectors. You can use either Euler Rotations or Quaternion Rotations to accumulate your rotations (I've come to really appreciate the quaternion approach for a variety of reasons).

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