Selecting units in 3d environment

Started by
5 comments, last by Zakwayda 18 years ago
What is a good technique for selecting units with the mouse in a 3d world? I'm thinking the best would be to project the positions of the units onto the plane of the screen (like the monitor) and then check where the mouse is, or where the bounding box is created by a click and drag. I can't quite think of how to go about doing the projection is the only problem. It's been a while since my linear algebra class. If anybody could tell me this I would be grateful. I'm just using basic rotation and translation calls to "position the camera", no gluLookat or anything. Of course, if anybody has a better way of approaching the problem, any comments are welcome as well. Thanks, Jake
Advertisement
There are various ways to do this, but (for various reasons), I tend to recommend a geometric world-space approach. (Screen space might work as well, though.)

The general gist of things is to create a picking ray or volume from your current camera parameters, and then build a list of objects in the world that intersect it. You might then select the closest, or perhaps select all of them if you're implementing 'drag enclose' like in many RTSs.

The objects themselves can be represented by proxies for this purpose, most likely spheres or AABBs; this will help with performance and will probably be accurate enough for most purposes. A broad-phase step can further accelerate this process.

The technical obstacles are basically a) intersecting the ray or volume with the proxy shapes in question, and b) constructing the pick ray or volume. The latter is probably the trickier of the two, and is at least somewhat API-dependent, so perhaps you could tell us what you're using.

[Edit: Just to be clear, although I've always done it geometrically, a screen-space solution might be just as good. The problem (projection or unprojection) is basically the same, although the intersection tests required will be simpler with the screen-space version.]
I'm using OpenGL. I think I'm leaning towards the screen space solution because of what you said, simplicity.
Quote:Original post by CodeZero
I'm using OpenGL. I think I'm leaning towards the screen space solution because of what you said, simplicity.
Assuming you have them available, look into the functions gluProject() and gluUnproject(). The former will be most relevant for the screen-space method, and should do most of the work for you. There are a few potential issues with the screen-space method (with regard to accuracy and object size), but I imagine they can be resolved as you encounter them.
I was unaware (obviously) of these 2 functions, and I think they will prove to be most useful, both for projecting units for my current dealings and for placing things on the map as well. Thanks very much for the help.
There is a nasty trick you can do it OpenGL that's much easier to code that picking rays.

1. Disable lighting and textures.
2. Render your scene into the back buffer, each unit with its own color.
3. Find the color of the pixel under the mouse cursor.
4. The unit that has that color is the one you clicked on.

I don't know if it works for click-drag selections, but for simple clicking on a single unit it's perfect. Plus, you don't need to worry about units occluding each other, you will always select the one in front.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by deathkrush
There is a nasty trick you can do it OpenGL that's much easier to code that picking rays.

1. Disable lighting and textures.
2. Render your scene into the back buffer, each unit with its own color.
3. Find the color of the pixel under the mouse cursor.
4. The unit that has that color is the one you clicked on.

I don't know if it works for click-drag selections, but for simple clicking on a single unit it's perfect. Plus, you don't need to worry about units occluding each other, you will always select the one in front.
Can't say for sure, but I bet that'll be a lot less efficient than using gluProject() and picking in screen space. As for selecting the closest, you can just choose from the selected entities the one that's closest to the view plane (just a vector subtraction and a dot product).

I would also guess that the screen space method would be easier to code than the framebuffer method (although as you suggest, the framebuffer method may be easier than the world-space approach).

This topic is closed to new replies.

Advertisement