3

I would like to implement scene picking (for mouse clicks, moves, etc.). What is the best, fastest way? I used to use glSelectBuffer and glRenderMode with GL_SELECT and then render whole scene again (of course with boost, without textures, heavy shaders, etc.).

It's too slow render recursively all nodes and geometries for one number (geometry ID) on every mouse click, move and drag. Does anybody know better way?

EDIT: Solution with reading depth buffer seems fain, but what if I don't want to pick some geometries and they are already drown to buffer? Finding box which contains point can be imprecisely, since point can be in multiple boxes.

Is it possible to write into two frame buffers, depth buffers in one draw? Then I can write geometry id to one buffer through shader. And what about speed?

eSeverus
  • 552
  • 1
  • 6
  • 18

2 Answers2

6

Since I'm new here, I can't answer Joe directly so I'll do it here. I never tried his way of doing this, so I'm not sure if it will work for you. Hopefully it will, if not: I'll give you my version. There are a number of ways you can do it. Rendering the whole scene again seems like an overkill.

The way I do it is an OBB-Ray intersection test. You consider Object-Oriented Bounding Boxes around your geometry and detect if they collide with the ray coming from you mouse click. If you need less precision I'd say go for AABB or even Sphere. More precision: convex hull. Just be aware of the fact that the less precision you ask for, the faster the algorithm. It might be an overkill but consider using a physics library for accelerated calculation like Bullet or PhysX if you don't want to implement the algoritms yourself. And another way is an OpenGL hack which I haven't used before.

All these ways to do it are explained here: http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/

Tom Quareme
  • 96
  • 1
  • 5
  • 1
    Indeed, with modern versions of OpenGL GL_SELECT and the selection buffer are gone. Either do a raycasting implementation, or you can do something similar to GL_SELECT; render the scene using a custom shader that writes object IDs to a framebuffer object. Read back the FBO pixels to get the ID of the object under the mouse cursor. – MichaelM Jan 20 '15 at 01:30
  • Thanks for your version, but I would like to to it with pixel precision. This is not comfortable for me, because I must import some physics library, but it seems fast and multiple intersections what is good. – eSeverus Jan 24 '15 at 13:57
  • No problem. If you want to implement the algorithms yourself I recommend the book Real-time Collision Detection by Christer Ericson or reading the source code of Bullet on Github to implement only what you need. – Tom Quareme Jan 25 '15 at 16:35
5

In the past I've used glReadPixels( xf, yf, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zf); to read the value of the depth buffer at a point (xf, yf) in screen space. You can then unproject this point back into world coordinates (multiply by the inverse of the modelview and projection matrices. This can be done with gluUnProject provided you're happy including the GLU library in your application.

This gives you a coordinate, you then need to search through your objects to find one that has a bounding box that contains this coordinate. This object is the one selected.

I'd recommend searching for information on Unprojecting if you want more information about this, also https://www.opengl.org/archives/resources/faq/technical/selection.htm is helpful (and suggests other techniques you could use).

Joe
  • 1,479
  • 13
  • 22
  • This way seems nice, but is it fast enough read GPU depth buffer? In my case I must create FBO because during drawing one frame I may clear depth buffer several times. Is it still faster than other ways? Thanks. – eSeverus Jan 23 '15 at 19:17
  • 1
    It's sort of difficult to say what the very best technique will be without knowing exactly what you're doing. However, I would anticipate that reading the depth buffer (even if you have to use an FBO) would not be take enough time to stop your program from running interactively (provided it runs a little faster thant 60fps without). That said I wouldn't expect you to need to use FBOs so long as you think about the rendering order, and carefully chose the correct point to do the glReadPixels at. – Joe Jan 25 '15 at 14:36
  • 1
    Unfortunately the best answer to a lot of "will this run fast enough?" questions is "try it and see" – Joe Jan 25 '15 at 14:37