2

I am programming in Xcode / OpenGL and have some 3d objects displayed in my view. Is there a way I can retrieve in OpenGL the 3D location / vertex / face I clicked on ?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Laurent Crivello
  • 3,809
  • 6
  • 45
  • 89
  • See also [this answer](http://stackoverflow.com/questions/2093096/implementing-ray-picking/2093149#2093149). – Damon Jul 25 '11 at 12:50

2 Answers2

3

The usual way to do this is by calling gluUnProject twice, with your x and y coordinates in both cases, and znear in one, and zfar in the other case.

That gives you two points through which a ray goes. Your mouse click is on that ray.

Now collide objects (first bounding volumes, then per triangle if you want, or parametrically if possible) with that ray. The closest hit is the one you want.

A different possibility would be to read back the z-buffer value (glReadPixels). This should be done with a pixel buffer object and spread over several frames (or it will be a very nasty stall on your pipeline). That will give you a 3D coordinate, for which you can find the closest object.

Or, you could use occlusion queries (redrawing a 1x1 viewport with color writes disabled) for the same effect.

Lastly, there is of course selection mode, but this is deprecated functionality, so you will probably not want to use it.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • Thanks, let me try the different possibilities. Which one would you recommend ? – Laurent Crivello Jul 25 '11 at 19:09
  • The first one is the preferrable one, since it does not stall the pipeline and is relatively simple math. If that is no option, I would read back the z buffer. – Damon Jul 25 '11 at 19:30
  • Thanks. I've tried to implement it, almost successfully. The issue is that when my model has been rotated and translated, I don't now what his new coordinates are to be able to test the collision. Any hint ? Thanks ! – Laurent Crivello Jul 28 '11 at 09:29
  • Coordinates are transformed using a matrix multiplication (of a single matrix which is composed of several individual ones, see pages 40-41 [here](http://www.opengl.org/registry/doc/glspec21.20061201.pdf)). You can retrieve the `GL_MODELVIEW_MATRIX` with `glGet`, but this is less efficient than possible, and includes the view transform. It is better to cache the value of the MODEL part of the MODELVIEW matrix before sending it to OpenGL or before adjusting your virtual camera. Then you can just do a matrix multiply on any coordinate to transform it from "model" to "world" space. – Damon Jul 28 '11 at 09:40
  • There is by the way [GLM](http://glm.g-truc.net/), which provides pretty much every possible function that you may need for manipulating matrices/vectors in a way that is compatible with OpenGL/GLSL, in case you don't have your own library. – Damon Jul 28 '11 at 09:42
  • Thanks for your answers Damon. Small newbie questions: I understand that I have to keep the Model coordinates (basically the ones I submit to OpenGL before rotated/translated), and multiply each point by the "matrix" : But how do I retrieve this matrix, is this the Quaternion made of rotate in columns 1-3 / translate in column 4 ? Thank you ! – Laurent Crivello Jul 28 '11 at 10:20
  • It very much depends on how you keep track of your objects in your program. If you use quaternion + translation vector, then it is a rotation matrix created from your quaternion, and having the translation vector in elements 12, 13, and 14 (the rightmost column). Luckily, for rotate-first-then-translate, the math is as easy as "fill translate in 12,13,14 - it's more complicated otherwise). It also depends on whether you do your own stuff and glLoadMatrix, or use glRotate and glTranslate etc. If you use glLoadMatrix, just cache what you have. Otherwise, you have to glGet the modelview matrix... – Damon Jul 28 '11 at 10:26
  • ... _before_ you do the glTranslate and glRotate for your virtual camera. That will still be the modelview matrix, but without the "view" bits applied yet (which is just the information that you want!). – Damon Jul 28 '11 at 10:27
  • I actually keep my camera on the center and don't touch it with gluLookAt, and do only glRotate/glTranslate on my objects. So basically, I recover my quaternion matrix with glGet, and multiply it with a point coordinate right ? To be able to multiply it, should I have my point coordinates in a 4x1 array ? i.e. [x y z 0] and multiply by the matrix ? Any idea of which GLM function helps me with it ? Thank YOU ! – Laurent Crivello Jul 28 '11 at 10:36
  • @LaurentCrivello let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1919/discussion-between-damon-and-laurent-crivello) – Damon Jul 28 '11 at 10:52
  • OK, I finally found it, thanks to all your help. Basically I had to invert the 4x4 matrix and multiply it by my camera's relative position to the scene. Thanks again ! – Laurent Crivello Jul 28 '11 at 14:23
2

Another way to do it if you are okay with using something that's deprecated in newer opengl versions is using the picking buffer/selection mode: http://www.lighthouse3d.com/opengl/picking/