 # gluUnProject

How do I use gluUnProject, some code would be appareciated, because I don’t get it… gluUnproject reverses the projection processes. Projection “flattens” a scene onto a plane in much the same way your shadow is projected onto the ground. (Of course, there are differences, since the object is between the “focal point” and the image plane in the shadow analogy. but. eh mathematically, opengl’s projection looks like:

v’=PMv

where v is a 4x1 homogeneous 3D coordinate, P is the 4x4 projection matrix, M is the 4x4 modelview matrix and v prime (v’) is the 4x1 homogenous point on the image plane (ie. on the screen).
“Classic” projection has P as a 3x4 matrix, v as a 4x1 vector and v’ as a 3x1 vector because depth is lost. The OpenGL projection matrix scales the z coordinate of the point in world coordinates to a number between 0 and 1 representing the distance as a ratio on the view frustum (ie. points on the near plane are mapepd to 0 and points on the far plane are mapped to 1). This value is stored in the depth buffer for hidden surface removal.

So! The projection process turns a 3D world coordinate into a 2D image point and corresponding depth point. gluUnproject does the reverse of this: it takes a 2D image point and corresponding depth point and finds what world vector would generate that point. This can be done in the OpenGL case because it stores (or, knows about) the z value in v’, and thus there is a 1-1 and onto mapping from three space to the image plane. (In “classic” projection this isn’t the case, since many 3D points can give rise to the same 2D point and the 3x4 projection matrix isn’t invertible).

I could give an example, but you’d likely think it was contrived to illustrate the point. But the psuedo code looks like:

float world_vector={1, 2, 3, 1}; /* homogeneous 3D point */
float projected_vector;
float recovered_vector;

projected_vector=gluProject(world_vector);
recovered_vector=gluUnproject(projected_vector);
assert(world_vector==recovered_vector);

hope this helps!
cheers,
John

Thanx, but all that advanced stuff just confused me, but the code was good, except that I don’t use gluProject, so I still fon’t get it… Here’s some code from my problem:

glViewport(0, 0, 640, 480);
glOrtho(-640, 640, -480, 480, -100, 100);

glutSolidSphere(100, 100, 100);
// at 0,0,0

void glutMouse(int button, int state, int x, int y)
{
glGetDoublev(GL_MODELVIEW_MATRIX, &one);
glGetDoublev(GL_PROJECTION_MATRIX, &two);
glGetIntegerv(GL_VIEWPORT, &three);

gluUnProject(x, y, 1, &one, &two, &three, &x2, &y2, &z2);

//This makes the application to hang…

//Here I want something like “x, y” == ball then killball…

I’m a total newbie so this could be totally wrong, but I have to try… Please help me, if somebody out there got it… /CyBBe, the newbie

I can see something that might lock your computer. It’s in your gluUnProject function. The fourth, fifth and sixth argument should be pointers, not pointers to pointers. one and two shoule be declared as float one, two and three as int three.
Then you sould pass then as one two and three, not &one, &two and &three.

Another thing you might wanna have a look at, is the third argoment. Your ‘1’ means a point on the far clipping plane. ‘0.5’ would mean a point in the middle of near and far clipping plane. You must extraxt the value from the z-buffer, and then normalize it in some way, to know the exact point in 3D space that represent that point on screen (including depthbuffer).

Thanx both of U, now it works, BUT…

The WinX works perfect, but the WinY doesn’t… Why? Does it have something to do with the WinZ??? How can I use WinZ?

Thanx…

The winy coord can be a small trap. The y-axis is going upwards, not downwards, on the screen. This means that y=0 is the bottom row of the window, and if your window is 100 pixels high, y=99 is the top row.

I think you could try out a different approach: selection buffer.
As I could understand, you need to detect the object on which the user clicks the mouse button. The best way to go for this, is use the GL_SELECT render mode. There are many postings on this subject, so I will not rediscuss the way to do it, here.