2

我想在 3D 中获得鼠标点击位置。下面是我的代码,很简单,有什么问题。我在哪里做错了..?为什么我没有得到 x 和 y 的确切值?任何的想法 ?

void glPerspective()
{
    glViewport(0, 0, WINDOW_SIZE_W, WINDOW_SIZE_H);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLdouble)WINDOW_SIZE_W / (GLdouble)WINDOW_SIZE_H, 0.1, 100000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, m_zoom,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();    
      glPerspective();     // perspective view
      Some_rotation_and_translation();
      glGetDoublev( GL_PROJECTION_MATRIX, OGLMprojection );
      glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview );
      glGetIntegerv( GL_VIEWPORT, OGLMviewport );
      Render_Triangular_model();
    glPopMatrix();
    swapbuffer();
}
    GLpoint GetOGLMousePos(GLint x, GLint y)
    {
        GLdouble winX = 0.0, winY = 0.0, winZ = 0.0;
        GLdouble posX = 0.0, posY = 0.0, posZ = 0.0;
        winX = (float)x;
        winY = (float)OGLMviewport[3] - (float)y;           // invert winY so that down lowers value
        glReadPixels( x, GLint(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
        gluUnProject( winX, winY, winZ, OGLMmodelview, OGLMprojection, OGLMviewport, &posX, &posY, &posZ);
        return GLpoint(posX, posY, posZ);
    }
4

2 回答 2

4

我认为当您调用glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview ). 该矩阵表示从局部对象坐标到世界坐标的变换。

我很确定gluUnProject假设它使用视图变换矩阵进行操作,该矩阵从世界坐标映射到相机空间坐标。

所以,我认为这是不匹配的问题,并且可以通过将 glGet* 调用移出 glPushMatrix - glPopMatrix 块来解决。

实际上,我认为获取GL_PROJECTION_MATRIXandGL_VIEWPORT是可以而且应该在鼠标功能中完成的事情,如本示例所示(由Tomas Hamala 提供):

/*
    gcc -Wall -lglut -lGLU -lGL unproject.c -o unproject
 */
#include <GL/glut.h>

void Display();
void Reshape(int w,int h);
void Mouse(int button,int state,int x,int y);

int main(int argc,char **argv) {
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(100,100);
    glutCreateWindow(argv[0]);
    glutDisplayFunc(Display);
    glutReshapeFunc(Reshape);
    glutMouseFunc(Mouse);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);

    glutMainLoop();
    return 0;
}

GLdouble ox=0.0,oy=0.0,oz=0.0;
void Display() {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(10.0,0.0,20.0,0.0,0.0,0.0,0.0,1.0,0.0);

    glPushMatrix();
    glRotatef(45,1.0,0.0,0.0);
    glutSolidTorus(4.0,5.0,20,20);
    glPopMatrix();

    glPushMatrix();
    glDepthMask(GL_FALSE);
    glTranslated(ox,oy,oz);
    glutSolidSphere(0.5,15,15);
    glDepthMask(GL_TRUE);
    glPopMatrix();

    glFlush();
}

void Reshape(int w,int h) {
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0,(float)w/(float)h,5.0,30.0);
    glMatrixMode(GL_MODELVIEW);
}

void Mouse(int button,int state,int x,int y) {
    GLint viewport[4];
    GLdouble modelview[16],projection[16];
    GLfloat wx=x,wy,wz;

    if(state!=GLUT_DOWN)
        return;
    if(button==GLUT_RIGHT_BUTTON)
        exit(0);
    glGetIntegerv(GL_VIEWPORT,viewport);
    y=viewport[3]-y;
    wy=y;
    glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
    glGetDoublev(GL_PROJECTION_MATRIX,projection);
    glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
    gluUnProject(wx,wy,wz,modelview,projection,viewport,&ox,&oy,&oz);
    glutPostRedisplay();
}

这是一个完整的工作示例,因此即使您无法修复现有代码,您也可以使用它。

希望有帮助。

于 2012-10-11T22:45:58.373 回答
2

感谢您宝贵的时间。现在它解决了。我在下面提到了这个问题。通常我们在编程过程中会忽略(浮点或双精度)变量,我认为我们不应该这样做。

GLpoint GetOGLMousePos(GLint x, GLint y)
{
GLfloat winX = 0.0, winY = 0.0, winZ = 0.0;       **// never ever make a mistake between float and double.
I wasted my 4 days to solve this and the problem was, I was using GLdouble here instead of GLfloat.
Try GLdouble here you will see a hell difference in output values.**


GLdouble posX = 0.0, posY = 0.0, posZ = 0.0;
winX = (float)x;
winY = (float)OGLMviewport[3] - (float)y;   // invert winY so that down lowers value
glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
gluUnProject( winX, winY, winZ, OGLMmodelview, OGLMprojection, OGLMviewport, &posX, &posY, &posZ);
return GLpoint(posX, posY, -posZ); // invert z value
}
于 2012-10-12T09:08:24.993 回答