使用gluUnProject()在光标位置绘制四边形

时间:2010-11-09 14:32:14

标签: opengl screen coordinates sdl translate

我正在使用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;
}

2 个答案:

答案 0 :(得分: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;以确保四边形出现在我点击的位置上方,它似乎按照我的预期工作。

答案 1 :(得分:0)

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

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

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

如果设计中没有基本原理,那么为Z设置默认值是一个坏主意。

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

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