3D Point selection

Started by
7 comments, last by dpadam450 17 years ago
Hi everyone, I have a 3D terrain (heightmap) and all i want to do is, when a mouse click is done on it, get the actual 3d coordinates of the object, not the mouse coords. I've tried with the mouse picking technique, with a 1x1 picking region, but all i get is that the object is selected. How can i get the selected point ? Thanks a lot !
Advertisement
You may want to give gluUnProject a try. It will convert your mouse coords to 3D coords. It works something like this.

//get matrix infoglGetIntegerv(GL_VIEWPORT, viewport);glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);//get mouse position, convert to opengl originwinx = LOWORD(lParam);winy = viewport[3] - HIWORD(lParam);//read the depth at mouse position, this is needed for gluUnProjectglReadPixels(winx, winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz);//get the 3D coordsgluUnProject(winx, winy, winz, mvmatrix, projmatrix, viewport, &objx, &objy, &objz);


Hope this helps.
DG
Thanks for your reply DG,

I 've tried it, but all i get are coordinates with incredibly high values (coords like 1234567345,348973498,-239487928), and i'm not sure if these values are reliable.

Besides, i'm not sure if i can get the selected point without picking, because i load the terrain from a .raw file, and i'd be interesting to know the selected point, not just the point where you click on the screen, but i don't know how to get it


Thanks anyway !
When you say selected point, do you mean the nearest point on the heightmap closest to where the user clicked? Or do you want the actual 3D point the user clicked on?

Where the user clicked on the screen is important for knowing where the point is in 3D space, since the 3D scene ends up mapped to your 2D window. The winz value is the depth of that pixel so opengl knows that it needs to draw pixels that are closer to the camera on top of ones that are further away from the camera. If you've drawn a heightmap and you haven't disabled writing to the depth buffer then you should be able to get a valid pixel depth from glReadPixels if you've given it a point that is actually over the heightmap.

What is glReadPixels giving you as a winz value, this should be between 0 and 1. 0 is on the near plane and 1 is on the far viewing plane, your heightmap is probably somewhere in the middle.

As for picking/selection I'm not sure if you need it or not, you may need it, so I guess you can name all the tiles of your heightmap and then you would know which tile the user clicked on. But since it's a heightmap that you probably choose the location for you could easily enough figure out which tile was clicked on by using gluUnProject.

I'm also using standard win32 mouse messages to get the location the user clicked on, I hope this works with your code or that you have converted to what ever method you are using.

DG
I keep an extra array the same size as the terrain's size. When someone clicks, I get the current modelview and projection matrix, etc. Then get the points in screen space to compare with the mouse's x,y coords. Then you can look up the corresponding points in the terrain.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

DG,

Thanks again for your answer.

I mean the actual point where the user clicked. I've tried again with gluUnProject and, as i told you, i get extremely high values, like (1193534109,1084497046,405412877), and i don't understand how can i get such a high z value when i defined znear=0.1 and zfar=10000.

By the way, i'm not using win32, i'm only using glut
-----------------------------------------------
dpadam450,

Sorry, but i'm not sure if i've understood you well, i'm quite new at OpenGl...

What do you mean when you say "Then get the points in screen space to compare with the mouse's x,y coords" ? How do i relate the mouse point to the extra array ? Could you please extend yourself a little bit ?

Thank you vey much

Dani

I use the following to get the mouse coords.

XPos = GET_X_LPARAM(lParam);YPos = GET_Y_LPARAM(lParam); 


And then use:

GLint viewport[4];GLdouble modelview[16];GLdouble projection[16];GLfloat winX, winY, winZ;GLdouble posX, posY, posZ;glGetDoublev( GL_MODELVIEW_MATRIX, modelview );glGetDoublev( GL_PROJECTION_MATRIX, projection );glGetIntegerv( GL_VIEWPORT, viewport );winX = (float)XPos;winY = (float)viewport[3] - (float)YPos;glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);


to get the figures in 3D. (Code "stolen" from elsewhere on gamedev.net)

seems to work ok...
A solution that doesn't involve gluUnProject would be to create a ray that passes through the point on the screen that you clicked, then find the intersection of that ray and the height map. The solution of that intersection is the point you're looking for.

Do research of rays, frustums, and picking.
What I was suggesting is you find the actual screen coords of each vertex. So you have your terrain model right?

GLfloat terrain_model[3 x num_vertices]; //x,y,z 3d

You then setup your projection/modelview and let opengl render your terrain. Well if you do the math the opengl performs to draw stuff on the screen, then you can figure out the screen coords of each vertex. To do that you need to have an extra array (you dont want to modify your actual terrain).

GLuint 2d_points[2 x num_vertices]; // x,y 2d


If you didn't get that then I can say best, you have 3d and 2d space, your trying to put the mouse from 2d to 3d, where I am saying put the vertices from 3d to 2d.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

This topic is closed to new replies.

Advertisement