Clicking in 3D space?

Started by
7 comments, last by GameDev.net 24 years, 3 months ago
oh i really need this info too! i know that the genesis3D engine does it somehow in CAMERA.C in the function geCamera_ScreenPointToWorld, except with all of that geVec3d and geXForm3d stuff it just confuses me (and makes me think of a GeForce). goto http://www.genesis3d.com for the free engine. i would appreciate any help on how to get it working using directx. thanks!

------------------
http://members.xoom.com/mutex0


Advertisement
What we did in JAKKAL was to render the objects within view and maintain a record of their projected x,y center points. Since the objects are sorted from front to back, we simply get the distance from the projected points to the mouse click point and took the objected with the smallest projected distance as the picked object. Object radius also was taken into account. This method is quick, but not perfectly accurate.

------------------
--Shannon Schlomer, BLAZE Technologies, Inc.

--Shannon Schlomer, BLAZE Technologies, Inc.
If you happen to be using OpenGL, the most effective way is to use the Select Buffer.

What it does is test render a small section of the scene that you specifiy with the gluPickMatrix() function. In your case, a couple pixels around the mouse click point would be a good rectangle.

In your rendering engine, you give every object in your scene a unique ID number called a "name".

Once the render pass is complete, the ID numbers of the objects that are drawn in your picking area are copied to a buffer that you supply. (note that nothing is actually drawn, it only generates the appropriate geometry in memory) three values of additional information is also copied into the buffer, such as depth information. Every fourth value in the buffer is the id number of the object selected. Note that if multiple objects overlap, you get more than one record in the select buffer. You sort these based on the depth values also supplied to determine which object you actually contacted.

further 3d math can then be done to determine the world coordinate of the mouse click, based on the position of the object selected.

Other libraries may use a different approach, but the only one I use is OGL. It is also not too difficult to write this functionality yourself, as long as you have access to clipping information in a rendering pass.

For more info on the Open GL way of doing things, look at the following functions:
glLoadName()
glSelectbuffer()
glRenderMode() (GL_SELECT and GL_RENDER)
gluPickMatrix()

Also, a simple example of this functionality can be found at http://home.att.net/~bighesh/ogl_sf.html

hope this helps a bit.

what if the world is essentially 2D? all i really need is a way to generate a vector from the camera pointing in the direction of the mouseclick. then i just test for intersection with objects on screen.

If you've already converted the points from the 3D world to the 2D screen you could then check the x/y values of your object and compare that to your mouse location. You could also make all the clickable object on the screen regions and check to see if the mouse click is within any of those regions.
I wrote my own engine so I don't know if OGL or some other engine will allow that.
You'll need to 'unproject' the mouse x/y coordinates. Assuming you have the matrix that you are using to transform your scene into 2D for viewing and a few matrix functions you're all set. Pass in the mouse point as 3 space with the z coord being from 0.0 - 1.0. Set the z-coord to the 'depth' you want to project at (0 is closest to the camera, 1.0 is the furtherest depth value determined by your projection).

1.)You'll need to normalize the mouse x/y coords:
mouseNorm.x = ((mouse.x-windowTopCorner.x) * 2.0 / window.width) - 1.0f;
(same for y using height and y values of course)

2.) Calculate the inverse of the current model/view and projection transforms (say for OpenGL):
glGetFloatv(GL_MODELVIEW_MATRIX, &mvMat);
glGetFloatv(GL_PROJECTION_MATRIX, &projMat);
Matrix M = projMat * mvMat; // order important in matrix math
Matrix invM = M.Inverse();

-Obviously you'll need functions or classes to do the matrix mults and inversion.

3. Transform the normalized mouse coords by this inverted matrix you have, use a homogenous coordinate (it has a 'w' or 4th value).

Vector4 tv = invM.Transform(mouseNorm);
mouseInWorld.x = tv.x / tv.w; // do the perspective division for the x/y/z.

Now you've got a 3d point under the mouse cursor at the nearest depth (or z) coordinate in the world.

To use this in a line hit-test for the whole world I would unproject the mouse x/y twice with 0.0z and 1.0z and thus create a line from the mouse click into the world.

[This message has been edited by Steve Sinclair (edited December 27, 1999).]

The previous posts have given some really complete answers, but since I just recently had to figure this out using DX7, I figured I would give my solution. I'm not claiming this is the best way to do it, but at least I know it works. Anyway, I made a VB to hold the original vertex data (D3DLVERTEX format in my case) and filled it with the untransformed vertices. Then I create another VB of same size to hold the transformed vertices (D3DTLVERTEX). Then process the vertices from the first VB into the second VB. Now the second VB's vertices contain the screen coordinates in the sx and sy members of the D3DTLVERTEX structure for each vertex. So you can lock() the second VB and check your mouseclick against any of the points.
OK, I'm trying to work out how to resolve a mouse click on the screen to a location in 3D space.

I've gotten as far as figuring out that you would project a ray from the camera, through the clicked point in the field of view... then I start thinking about the angle of the camera, angle of the scenery... and I lose it. I'm sure I'm not the first person to wonder about this, yet I can't turn anything up on the net - any links or references would be greatly appreciated.

Thanks!

Mike
mike@planetofthegeeks.com

Yeah, basicaly what I said. Once the points are converted from 3D to 2D, you don't have any z coordinate to worry about.

------------------
E:cb Woof!

This topic is closed to new replies.

Advertisement