Incorrect 3D coordinates from 2D mouse click ?

Started by
8 comments, last by luckyyyyyy 11 years, 6 months ago
I want to get the mouse click position in 3D. Below is my code, its simple, I am not doing wrong in it but I don't know why I am always getting X and Y values are wrong. I think Maximum X = 0.072345664 and Y = 0.04124355 . something like this. where I am doing wrong.. ? Why I am not getting the exact values of x and y ? Z value is OK. Only issue with X and Y. any idea ? Thanks



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();
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;
GLint OGLMviewport[4]; //stores viewport information
GLdouble OGLMmodelview[16];
GLdouble OGLMprojection[16];
glGetDoublev( GL_PROJECTION_MATRIX, OGLMprojection );
glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview );
glGetIntegerv( GL_VIEWPORT, OGLMviewport ); //transfers viewport info into viewport array.
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);
}


Output 3D coordinates (top right section of the OpenGL display screen):

-0.000810418, 0.0011706, 99.9
0.00288149, 0.00126065, 99.9
0.00981506, 0.00144074, 99.9
0.0157581, 0.00171088, 99.9
0.0249429, 0.00171088, 99.9
0.0367389, 0.00180093, 99.9
0.0468241, 0.00180093, 99.9
0.0557387, 0.00225116, 99.9
0.065914, 0.00243125, 99.9
-0.000990511, 0.0105354, 99.9
-0.0013507, 0.017379, 99.9
-0.0013507, 0.0225116, 99.9
-0.00171088, 0.0268338, 99.9
-0.00171088, 0.0313362, 99.9
-0.00207107, 0.0380896, 99.9
0.0724874, 0.0404308, 99.9
0.0744684, 0.0411512, 99.9 // top right corner



Think of Design with Dimensions
http://real3d.pk
[/quote]
Advertisement
My guess is that is is somewhere in the GLpoint class. Your code is nearly exactly like mine and it works for me. How do you define GLpoint? That isn't part of OpenGL.
hey dude first thing is your perspective calculation (the z near z far problem!)



void T3DPlanet::GetOGLPos(int x, int y, t3dpoint & np, t3dpoint & fp)
{
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
// glGetDoublev( GL_PROJECTION_MATRIX, projection );
glMatrixMode(GL_PROJECTION); // Change Matrix Mode to Projection
glPushMatrix();
glLoadIdentity(); // Reset View
gluPerspectiveA(90.0f, DISPLAY_WIDTH/DISPLAY_HEIGHT,1000.0f, 2000.0f); // Do the perspective calculations. Last value = max clipping depth
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glPopMatrix();
glMatrixMode(GL_MODELVIEW);

// int i;
// for (i=0; i<16;i++) ShowMessage(FloatToStr(projection));
glGetIntegerv( GL_VIEWPORT, viewport );
double nx,ny,nz; double fx,fy,fz;
float winX = float(x);
float winY = float(viewport[3]) - float(y);
t3dpoint neara;
t3dpoint fara;
gluUnProject(winX, winY, 0, modelview, projection, viewport, &nx, &ny, &nz);
gluUnProject(winX, winY, 1, modelview, projection, viewport, &fx, &fy, &fz);
np.x = nx;
np.y = ny;
np.z = nz;
NEAR_HIT = np;
fp.x = fx;// - nx;
fp.y = fy;// - ny;
fp.z = fz;// - nz;
FAR_HIT = fp;
}

and heres a thing that i use when mouse cursor is moving through window and it uses the proc above


[code]
void __fastcall T3DPlanet::MouseInsertMove(int X, int Y,HWND hwnd)
{

glViewport(0, 0, int( DISPLAY_WIDTH), int(DISPLAY_HEIGHT)); // Set the viewport for the OpenGL window
glMatrixMode(GL_PROJECTION); // Change Matrix Mode to Projection
glLoadIdentity(); // Reset View
gluPerspectiveA(90.0, DISPLAY_WIDTH/DISPLAY_HEIGHT,1000.0f, 1000.0 * 1000.0 * 1000.0 * 1000.0); // Do the perspective calculations. Last value = max clipping depth
glMatrixMode(GL_MODELVIEW);

sx = X;
sy = Y;
//glClear(GL_COLOR_BUFFER_BIT);
//glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
gluLookAt(EYEPOS.x,EYEPOS.y,EYEPOS.z,EYEPOS.x+EYELOOKATPOINT.x,
EYEPOS.y-EYELOOKATPOINT.y,EYEPOS.z-EYELOOKATPOINT.z,
0,1,0);
if (insert_mode == true) {
TPoint mouse;
GetCursorPos(&mouse); // Gets The Current Cursor Coordinates (Mouse Coordinates)
ScreenToClient(hwnd, &mouse);
t3dpoint np, fp;
GetOGLPos(mouse.x,mouse.y,np,fp);
t3dpoint vLine[2];
np = vectorAB(NEAR_HIT,FAR_HIT);
np = Normalize( np ); //nice one milion kilometers away ;u
np = vector_multiple(np, 1000.0f * 1000.0f * 1000.0f);
vLine[0] = NEAR_HIT;
vLine[1] = vectors_add(NEAR_HIT, np);
//
//
int i;
for (i=0; i<SCENE_SELECTION[0].selectedfaces.Length;i++)
if (LineIntersectFaceFromModel(SCENE_SELECTION[0].selectedfaces,PLANET_MODEL,vLine, HIT_SPACE_POSITION ) == true)
return;
}
glPopMatrix();
}
[/code]



Ah please dont ask me why i call perspective projection and loadidentity before getoglpos ( i cant remember!!!)
well i remember that just draw your scene then use getoglpos


but it returns me two POINTS (NOT THE DEPTH POINT or etc) just 2 points that make the line from screen to the outter space ;x
then i must find a collision point between polygon ray intersection


I think you can bypass ray poly intersection by reading the acutal depth value from image (by glReadPixels let assume that will be a var called KKK)

so then gluUnProject(winX, winY, KKK, modelview, projection, viewport, &nx, &ny, &nz); nx ny nz are output pos vals but i don't know if it works

===================

and here's a proove that it works :X but watch after 1 min :/

[media]
[/media]
I have tried everything but not getting the exact X and Y values. I am applying glPerspective() in real-time (display function) thats why I think I have to apply it with a specific matrix but i dont know which matrix. I do not want to select vertex or something like that I just need 3D coordinates at the click position.



Think of Design with Dimensions
http://real3d.pk
[/quote]
the func void T3DPlanet::GetOGLPos(int x, int y, t3dpoint & np, t3dpoint & fp)

void gluPerspectiveA(GLfloat fovy, GLfloat aspect, GLfloat zmin, GLfloat zmax)
{
GLfloat xmin, xmax, ymin, ymax;
ymax = zmin * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
glFrustum(xmin, xmax, ymin, ymax, zmin, zmax);
}



provides the correct X and Y values for mouse cursor,

The idea of my soulition is: (i will explain the code now)
the idea is as follows:
set z near and z far closely
gluPerspectiveA(90.0f, DISPLAY_WIDTH/DISPLAY_HEIGHT,1000.0f, 2000.0f);
set the camera

then check nearest depth val and the farthest, then make from them a line and test whatever you want

gluUnProject(winX, winY, 0, modelview, projection, viewport, &nx, &ny, &nz); //the point on your screeen! (depth value 0,0f)
gluUnProject(winX, winY, 1, modelview, projection, viewport, &fx, &fy, &fz); //pushed far away point (depth value 1.0f)

Maybye you are not familiar with the dpeth values they are from 0 to 1 (depending on znear/zfar value 0.75 from depth vcan be farther than 0.75 from diffferent znear/zfar perspective ble ble ble ble )


void T3DPlanet::GetOGLPos(int x, int y[..])
{
[...]
glGetIntegerv( GL_VIEWPORT, viewport );
float winX = float(x);
float winY = float(viewport[3]) - float(y);

//optional readpixels

//optional one gluunproject(winx,winy, readpixeldepth, modelview, projection, viewport, outputx,outputy,outputz);








if you do not want to make rays and then test some shit you use)
if you use glReadPixels() with the same x,y values (winX, winY) range 1 GL_DEPTH_COMPONENT (or GL_DEPTH_COMPONENT24)

after reading the depth value from the pixel you
call glunproject
heres is a pixel reading

void __fastcall READ_RGBA_FROM_OGL_WINDOW(int x,int height, int y, int & r, int & g, int & b, int & a)
{


unsigned char* pdata = new unsigned char[4];
glReadBuffer(GL_COLOR_BUFFER_BIT);

glReadPixels(x,height-y,1,1,GL_RGBA,GL_UNSIGNED_BYTE,pdata);

r = pdata[0];
g = pdata[1];
b = pdata[2];
a = pdata[3];
// delete B2;
delete [] pdata;
}

//so for depth is should be but i dont know if that is correct

float __fastcall READ_DEPTH_FROM_OGL_WINDOW(int x,int height, int y)
{

unsigned char* pdata = new unsigned char[1];
glReadBuffer(GL_DEPTH_BUFFER_BIT);
glReadPixels(x,height-y,1,1,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,pdata);

return float(pdata[0]) / 255.0f;

}



[color=#ff0000]I have tried everything but not getting the exact X and Y values. - no you didin't
[color=#ff0000]I am applying glPerspective() in real-time (display function) thats why
- I don;t understand, you display the scene and you store for it a modelview matrix, projection matrix , and viewport
so you can call fcking gluUnProject

and do not use so big ratio between z_near/z_far


[color=#ff0000]I think I have to apply it with a specific matrix but i dont know which matrix. - ah HELL NO !!!

[color=#ff0000]I do not want to select vertex or something like that I just need 3D coordinates at the click position.


So WHA THE HELL ARE YOU WAITING FOR?
CLEAN YOUR CODE


and do as follows


draw the scene

store modelview matrix and stroe viewport also
(when want to click)
change perspective to 'nicest z_near/z_far aspect ratio)
store projection matrix
call gluUnProject and get the values

be happy ;(


I still have no idea what are you doing wrong dude
haha.. I like the way u teaching.. ;)

I got your point.. i do not want any kind of line intersection of whatever. I just want that when I click on model I get 3D coordinates.

I did what u said at the end. But didn't get this ?
(when want to click)
change perspective to 'nicest z_near/z_far aspect ratio)

now tell me where I am doing wrong?


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, 10000.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);

glPerspective();

glPushMatrix();
glTranslatef(screenX, 0.0, 0.0);
glTranslatef(0.0, screenY, 0.0);
glRotatef(spin_y, 1.0, 0.0, 0.0);
glRotatef(spin_x, 0.0, 1.0, 0.0);
glRotatef(spin_z, 0.0, 0.0, 1.0);
glGetDoublev( GL_MODELVIEW_MATRIX, OGLMmodelview );
glGetDoublev( GL_PROJECTION_MATRIX, OGLMprojection );
glGetIntegerv( GL_VIEWPORT, OGLMviewport );

Render_Triangular_model();
glPopMatrix();
glutSwapBuffers();
}
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 - 1; // 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);
}



Think of Design with Dimensions
http://real3d.pk
[/quote]
i am having trouble with reading from depth buffer (reading the winZ) if i solve this i will post it, i think tommorow
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
}



Think of Design with Dimensions
http://real3d.pk
[/quote]
Lol i have compiled your code and did the same with this double (changed to float) but still cant read the winZ lol ; ]
remember to read pixels only when you have depth buffer filled with this what you want to check, do ont call getoglpos whenever you want because t might not work
haha.. NO i dont have any issue now... working like charm..
thanks to u.



Think of Design with Dimensions
http://real3d.pk[/quote]

This topic is closed to new replies.

Advertisement