Incorrect 3D coordinates from 2D mouse click in OpenGL?
-
06-07-2021 - |
Question
I want to get the mouse click position in 3D. Below is my code, its simple, What wrong in it. where I am doing wrong.. ? Why I am not getting the exact values of x and y ? any idea ?
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);
}
Solution 2
Thanks for your precious time. Now its solved. I mention the problem below. Usually we used to ignore (float or double) variables during programming, I think we should not.
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
}
OTHER TIPS
I think you're getting the world transform matrix for the "triangular model", when you call glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview )
. That matrix represents a transform from local object coordinates to world coordinates.
I'm pretty sure that gluUnProject
assumes that it's operating with a view transform matrix, which maps from world coordinates to camera space coordinates.
So, I think that's the mismatch, and one that can probably be fixed by moving your glGet* calls out of the glPushMatrix - glPopMatrix block.
Actually, I think getting GL_PROJECTION_MATRIX
and GL_VIEWPORT
is something that can, and should be done in the mouse function, as demonstrated in this example (by 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();
}
This is a complete, working example, so it's something you can work from, even if you're not able to fix your existing code.
Hope that helps.