3D picking

Started by
16 comments, last by Marianne 18 years, 7 months ago
Hi, i have a simple question about 3D picking for my 3D game... i've used the GLPicking selection mode, however i need somethnig different that can be done only with maths. i need to click somewhere on the 2D screen and get coords for where the click ends on 2 axises out of 3 (for exemple, assuming Y is always equal to 0, where does this click end on the X and Z axises? (for exemple, there's a ground at Y = 0 and from any view i'd like to know where it's been clicked on in 3D coords) thanks!
Advertisement
Probably the first thing you need is a picking ray; for this you need to be able to unproject a point in window coordinates. You can do this yourself if your math library supports matrix inversion and homogenous coordinates, or you can use gluUnProject(). I'm assuming that you are using the default OpenGL depth range of [0,1].

gluUnProject is of the form:
gluUnProject(    GLdouble windowx,    GLdouble windowy,    GLdouble windowz,    const GLdouble modelviewMatrix[16],    const GLdouble projectionMatrix[16],    const GLint viewport[4],    GLdouble* x,    GLdouble* y,    GLdouble* z);
You can query the matrices and viewport parameters from OpenGL using glGet*v(). x, y, and z are the output coordinates. windowx and windowy are in window coordinates where +y is up, so you'll probably need to invert your mouse y coordinate.

windowz is a depth value of your choosing. There are a couple of ways you can generate the ray. One is to call gluUnProject() once with a windowz value in the range [0,1]. The ray direction is then the resulting vector minus the camera position.

You can also call gluUnProject() once with windowz = 0 and once with windowz = 1, which gives you two points defining a segment that lies within the view frustum.

Once you have your ray, you can use it however you want, including intersecting with the ground plane as in your example.

I'll be happy to provide more details if you need them.
thanks, this looks very helpful!


i have done this functiuon with it:

void winToWorldCoords(GLdouble winX, GLdouble winY){    GLdouble* x; x=0;    GLdouble* y; y=0;    GLdouble* z; z=0;    GLdouble model[16]; glGetDoublev(GL_MODELVIEW,model);    GLdouble proj[16]; glGetDoublev(GL_PROJECTION,proj);    GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport);            gluUnProject(winX, winY, 0.0,                 model, proj, viewport,                 x,y,z);           cout << "x: " << x << " y: " << y << " z: " << z << endl;}


however, this causes a bus error and i really can't figure out why

and by the way, when i have the ray i'm not too sure how to calculate where it arrives at some point - i'm afraid my maths lack, i only know how to get the coords of a 2D ray

[Edited by - Marianne on September 3, 2005 2:43:05 PM]
    GLdouble x; x=0;    GLdouble y; y=0;    GLdouble z; z=0;gluUnProject(winX, winY, 0.0,                 model, proj, viewport,                 &x,&y,&z);


I would guess that's right.
Quote:and by the way, when i have the ray i'm not too sure how to calculate where it arrives at some point - i'm afraid my maths lack, i only know how to get the coords of a 2D ray
Looks like Ilici spotted the error in your code. As for your other question, I'm not sure what you mean by the ray ariving at some point. Do you mean how to intersect it with the ground plane or some other object? If it's the former, googling for 'ray plane intersection' should turn up the solution. Just watch out for the failure case where the ray is parallel to the plane.
thanks it works great for turning window coords into world coords! i'll see for the maths i've found a few websitesw, i'll try to get them to work - and if i can't i can fake it with my 2D maths i think (i'd just need twice more calculations i think)

thanks anyway i should be able to continue on my own without annoying you ;)
well guess i spoke too fastly... :/ your code works greatly however coords are always mapped to the center of teh screen no amtter what winodw coordinates i enter (i try printing everything, and no matter what window coords i give, i end up with the same space location) - what's wrong? thanks again
Hi,

There are too many variables to say for sure what's wrong, so if you haven't figured out the problem already perhaps you could post the following bits of code:

1. Where you set up the modelview matrix, projection matrix, and viewport
2. Where you query OpenGL for the necessary info and call gluUnProject()
3. Where you construct the ray (if you're getting that far)
well most of the interesting code is already up this thread but i'll post it again ;)

/*Where i set up the modelview matrix, projection matrix, and viewport*/void GL_reshape(int width, int height){    glViewport(0, 0, width, height);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    gluPerspective(45, (float)width/(float)height, 1.0, 200.0);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();}/*method that turns window coords into world coords - i have tried printing the window coords and they do vary, the problem is not there*/point3d toWorldCoords(GLdouble winX, GLdouble winY){    GLdouble x=0;    GLdouble y=0;    GLdouble z=0;    GLdouble model[16]; glGetDoublev(GL_MODELVIEW,model);    GLdouble proj[16]; glGetDoublev(GL_PROJECTION,proj);    GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport);gluUnProject(winX, winY, (GLdouble)1.0,                     model, proj, viewport,                     &x,&y,&z));        cout << "x: " << x << " y: " << y << " z: " << z << endl;   return new point3d(x,y,z); // point3d is a simple class holding x y and z variables to represent a 3d vector}
Hm, I'm not seeing where the error is...but maybe I'm missing it. If you're still trying to fix this, here are a few more ideas:

1. Go into the debugger and check the values of the queried modelview matrix and viewport parameters. Based on what you posted, the modelview matrix should be identity. Also see what the values of x, y and z are after the call to gluUnProject(). I can't imagine why cout would be outputting them incorrectly, but you might check them in the debugger just in case.

2. If you can, post your results. That is, show some sample window coordinates and the world coordinates you're getting back. I'd be happy to run the input through gluUnProject() and my own unproject() function and see if I get the same thing. You might also give your default window width and height.

I've successfully done this with both gluUnProject() and my own code, so I know it works. There's probably just some little detail throwing things off for you...

This topic is closed to new replies.

Advertisement