3

我正在将 SDL 与 OpenGL 一起使用,到目前为止,我已经完成了 2d 中的所有操作(使用 glOrtho())

现在我想尝试在 3D 中绘制东西,但是当然,因为我现在已经将第三维加入到混合物中,所以事情变得越来越复杂。

我想要做的是,获取光标的屏幕坐标,将它们转换为(?)世界坐标(我可以在 OpenGL 中使用的坐标,因为我现在有透视等),然后在该位置(鼠标光标位于四边形的中心)

我已经阅读了一些关于 gluUnProject() 的教程,并且我有点理解我应该做什么,但是由于我是自己学习的,所以很容易感到困惑并且不能正确理解我在做什么。

因此,我主要从我找到的示例中复制。

下面是我的代码(我拿出错误检查等试图减少一点)

如您所见,我有 mouseX、mouseY 和 mouseZ 变量,其中 mouseX 和 mouseY 从 SDL 获取它们的值。

我尝试使用 glReadPixel() 来获取 mouseZ,但我不确定我是否做得对。

问题是当我单击时,四边形没有绘制在正确的位置(我猜部分是因为我不知道如何正确获取 mouseZ,所以我只是在 gluUnProject() 中用 1.0 替换它?)

我在 glTranslatef() 函数中使用了新的坐标(wx,wy,wz),但又一次因为我不知道如何正确获取 mouseZ 我猜这是它不能正常工作的原因。如果我用 -499 替换 wz 它似乎可以正常工作,但我需要知道如何在不手动找到正确(或几乎正确)数字的情况下获得准确的结果

如果有人能告诉我我做错了什么,或者给我任何建议,将不胜感激。

#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

SDL_Surface* screen = 0;
SDL_Event event;
bool isRunning = true;

int mouseX, mouseY, mouseZ = 0;

GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realY; /* OpenGL y coordinate position */
GLdouble wx, wy, wz; /* returned world x, y, z coords */

int main(int argc, char **argv) {
    SDL_Init(SDL_INIT_EVERYTHING);

    screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);

    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);

    glViewport(0, 0, 800, 600);

    glClearDepth(1.f);
    glClearColor(0, 0, 0, 0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(90.f, 1.f, 1.f, 500.f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    while(isRunning) {
        while(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT) {
                isRunning = false;
            }

            if(event.type == SDL_MOUSEBUTTONDOWN) {
                if(event.button.button == SDL_BUTTON_LEFT) {
                    SDL_GetMouseState(&mouseX, &mouseY);

                    glGetIntegerv(GL_VIEWPORT, viewport);
                    glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
                    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
                    realY = viewport[3] - (GLint) mouseY - 1;
                    glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);

                    gluUnProject((GLdouble)mouseX, (GLdouble)realY, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
                }
            }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glPushMatrix();

        glTranslatef(wx, wy, wz);

        glBegin(GL_QUADS);
            glColor4f(1.f, 0.f, 0.f, 1.f);
            glVertex3f(-20.f, -20.f, 0.f);

            glColor4f(0.f, 1.f, 0.f, 1.f);
            glVertex3f(-20.f, 20.f, 0.f);

            glColor4f(0.f, 0.f, 1.f, 1.f);
            glVertex3f(20.f, 20.f, 0.f);

            glColor4f(1.f, 0.f, 1.f, 1.f);
            glVertex3f(20.f, -20.f, 0.f);
        glEnd();

        glPopMatrix();

        SDL_GL_SwapBuffers();
    }

    SDL_FreeSurface(screen);

    return 0;
}
4

2 回答 2

1

我发现如果我添加以下内容:

GLfloat depth[2];

然后将 glReadPixels() 从:

glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);

到:

glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth);

然后我只是将 gluUnProject() 从:

gluUnProject((GLdouble)mouseX, (GLdouble)realY, mouseZ, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

到:

gluUnProject((GLdouble) mouseX, (GLdouble) realY, depth[0], mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

然后我可以得到我想要的 Z 值。

然后我只是为 wz 添加了一个小值,例如:wz += 1;以确保四边形出现在我单击的位置上方,并且它似乎可以按我现在的预期工作。

于 2010-11-10T09:44:38.280 回答
0

要猜测一个 Z 你需要对这个 z 有意义:

通常的意思是你想将(相机原点,像素)对应的线与显示的 3d 对象相交。您可以为此使用 Z 缓冲区。

如果不是(您想将多边形粘贴到没有 3D 关系的光标上),只需使用 2D 功能,您可以在同一帧中绘制时在 3D 和 2D 投影之间交替(使用投影矩阵或 2D 特定功能) ),因此您不需要 z。

如果在您的设计中没有任何理由,则为 Z 设置默认值是一个坏主意。

只有一个 Z 值可以为您提供正确的像素坐标。

openGL 中 2D 和 3D 坐标之间的联系是 OpenGL 在 Z = 1 处使用投影平面。然后将像素坐标从 [-1,1] 缩放到像素坐标。

于 2010-11-09T14:45:04.267 回答