5
votes

I'm already able to find the world coordinates of the place i clicked, and it also checks this with the depth buffer. For this is used the following code :

GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX,winY;
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);

// obtain the Z position (not world coordinates but in range 0 - 1)
GLfloat z_cursor;
winX = (float)x_cursor;
winY = (float)viewport[3]-(float)y_cursor;
glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z_cursor);

// obtain the world coordinates
GLdouble x, y, z;
gluUnProject(winX, winY, z_cursor, modelview, projection, viewport, &x, &y, &z);

with x_cursor and y_cursor being my cursor coordinates.

So far so good and when printing x,y,z they seem to be good !

But now... After parsing my files containing all the polygons/triangles. I put everyting in openGL DISPLAY Lists. So my program basically just calls the lists, and translates/rotates them. Every object als has a unique name. So all i keep are the lists, I don't keep the points/triangles of every object

My Question :

So i have my world coordinates of where i clicked, but how can I figure out which object matches that position !?

4
What are "openGL Generic Lists"? - genpfault
If you kept the triangles and vertices associated with each object it would be trivial, right (find the triangle closest to x,y,z and return which object it belongs to)? Is there a reason why you don't keep them around? Another idea: assuming your objects are 'far enough' apart you could just check x,y,z against bounding volumes instead. @genpfault: I'm assuming he means display lists. - user786653
Move away from display lists, use vertex arrays/buffers and keep a RAM copy of your mesh. Then all you got do do is implement some simple ray picking. - Christian Rau

4 Answers

4
votes

If you just want the object ID and are willing to tolerate 2x overdraw:

1) Clear color and depth buffers

2) Draw all objects with different solid colors (disable lighting and texturing), maintaining a color -> object ID map.

3) Read color buffer at mouse position, note color and look up in color map.

4) Clear color and depth buffers and re-render scene as normal.

0
votes

Refer to the OpenGL Picking Tutorial. It contains a fully working example. However, it seems that code can still be improved if you only want to select the object closest to the camera (e.g. the one painted on top). You can modify the code to get this result, however.

void list_hits(GLint hits, GLuint *names)
{
    int i; int bestmatch; GLuint bestdistance;
    if (hits < 1) {
      return;
    }
    bestmatch = 0;
    bestdistance = names[bestmatch*4+1]; // min distance to object.
    for (i = 1; i < hits; i++)
    {
        distance = names[i*4+1];
        if (distance < bestdistance) {
           bestmatch = i; bestdistance = distance;
        }
    }
    printf("Hit: %d.\n", bestmatch);
 }

Caveat: I've done this before, but this particular code is not tested.

0
votes

Cast a ray into the scene from the point of view of the eye.

Compute the world space xyz location of the mouse click on the near plane by using vector arithmetic.

Here is a diagram of what you need to do:

enter image description here

This is more efficient than an unproject because unproject involves a matrix inverse (which is quite costly)

This is exactly the process you would use to cast a ray into a scene for a raytracer for the pixel that was clicked on. (In a ray tracer, you are retrieving the color, here you are retrieving the id of an object).