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

Opengl 使用gluUnProject()在光标位置绘制四边形,opengl,screen,coordinates,sdl,translate,Opengl,Screen,Coordinates,Sdl,Translate,我在OpenGL中使用SDL,到目前为止,我已经在2d中完成了所有工作(使用glOrtho() 现在我想尝试在3D中绘制东西,但当然,因为我现在已经在混合中加入了三维,事情变得越来越复杂 我想做的是,获取光标的屏幕坐标,将其转换为(?)世界坐标(我可以在OpenGL中使用坐标,因为我现在有透视图等),然后在该位置绘制一个四边形(鼠标光标位于四边形的中心) 我已经阅读了一些关于gluUnProject()的教程,我有点理解我应该做什么,但由于我是自学的,所以很容易感到困惑,无法正确理解我在做什么

我在OpenGL中使用SDL,到目前为止,我已经在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;
}
#包括
#包括
SDL_表面*屏幕=0;
SDL_事件;
bool isRunning=true;
int mouseX,mouseY,mouseZ=0;
闪烁视口[4];
GLM矩阵[16],projmatrix[16];
闪烁真实;/*OpenGL y坐标位置*/
GLWx,wy,wz;/*返回世界x,y,z坐标*/
int main(int argc,字符**argv){
SDL_Init(SDL_Init_EVERYTHING);
屏幕=SDL_设置视频模式(800、600、32,SDL_OPENGL);
glEnable(GLU深度试验);
glDepthMask(GL_TRUE);
glViewport(0,080600);
GLC清除深度(1.f);
glClearColor(0,0,0,0);
glMatrixMode(GL_投影);
glLoadIdentity();
(90.f,1.f,1.f,500.f);
glMatrixMode(GLU模型视图);
glLoadIdentity();
同时(正在运行){
while(SDL_事件和事件)){
if(event.type==SDL\u QUIT){
isRunning=false;
}
if(event.type==SDL_MOUSEBUTTONDOWN){
if(event.button.button==SDL_按钮左){
SDL_GetMouseState(&mouseX,&mouseY);
glGetIntegerv(GL_视口,视口);
glGetDoublev(GLU模型视图矩阵,mvmatrix);
glGetDoublev(GL_投影矩阵,projmatrix);
realY=视口[3]-(闪烁)鼠标-1;
glReadPixels(mouseX、realY、1、1、GL\u DEPTH\u组件、GL\u FLOAT和mouseZ);
glunproject((GLdouble)mouseX,(GLdouble)realY,1.0,mvmatrix,projmatrix,viewport,&wx,&wy,&wz);
}
}
}
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
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);
格伦德();
glPopMatrix();
SDL_GL_SwapBuffers();
}
SDL_自由曲面(屏幕);
返回0;
}

要猜一个Z,你需要知道这个Z的含义:

通常,其含义是希望将与(摄影机原点、像素)相对应的线与显示的三维对象相交。您可以使用Z缓冲区进行此操作

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

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

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

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

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

GLfloat depth[2];
然后将glReadPixels()更改为:

致:

然后我将gluUnProject()从:

致:

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


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

因此,为了检查我的理解,如果我想找到正确的Z值,我首先需要一个我想放置四边形的曲面?对于第一个选项,如果你想让四边形生活在3D空间中,请选择“是”。如果没有任何看起来像的对象,可以使用与摄影机方向正交的投影平面。正如你所说的,当你使用一个固定的Z时,它就是你所做的。但是你必须找到正确的Z来匹配像素坐标。这取决于你的投影矩阵。因此,我认为将投影矩阵切换到2D来绘制四边形更容易。
glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);
glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth);
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);