Неправильные 3D-координаты от 2D-щелчка мыши в OpenGL?

Я хочу получить положение щелчка мыши в 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);
    }

person maxpayne    schedule 11.10.2012    source источник
comment
Спасибо вам за настройку проекции и видового экрана из функции отображения. Просто примечание: glPushMatrix(), glPopMatrix неоднозначны; Я бы добавил к каждому из них вызов glMatrixMode, просто для корректности.   -  person datenwolf    schedule 11.10.2012


Ответы (2)


Я думаю, что вы получаете матрицу преобразования world для "треугольной модели", когда вызываете glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview ). Эта матрица представляет собой преобразование локальных координат объекта в мировые координаты.

Я почти уверен, что gluUnProject предполагает, что он работает с матрицей преобразования view, которая сопоставляет мировые координаты с координатами пространства камеры.

Итак, я думаю, что это несоответствие, и его, вероятно, можно исправить, переместив вызовы glGet* из блока glPushMatrix - glPopMatrix.

На самом деле, я думаю, что получение GL_PROJECTION_MATRIX и GL_VIEWPORT — это то, что можно и нужно делать в функции мыши, как показано в этом примере (от Томас Хамала):

/*
    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();
}

Это полный рабочий пример, поэтому с ним можно работать, даже если вы не можете исправить существующий код.

Надеюсь, это поможет.

person Goran Milovanovic    schedule 11.10.2012

Спасибо за ваше драгоценное время. Теперь это решено. Я упоминаю проблему ниже. Обычно мы игнорировали переменные (float или double) во время программирования, думаю, не стоит.

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
}
person maxpayne    schedule 12.10.2012