------------------
http://members.xoom.com/mutex0
Clicking in 3D space?
------------------
--Shannon Schlomer, BLAZE Technologies, Inc.
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.
I wrote my own engine so I don't know if OGL or some other engine will allow that.
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).]
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
------------------
E:cb Woof!