PDA

View Full Version : gluUnProject revisited



DalTXColtsFan
07-19-2003, 02:57 PM
Greetings all,
This is kind of the continuation of a thread below on gluUnProject - I'm trying to write a demo that draws a prism and allows the user to drag the prism around the XZ plane. I've updated the sourcecode in the page in my sig. Obviously what I'm doing now isn't working http://www.opengl.org/discussion_boards/ubb/smile.gif.

My idea:

What I'm thinking is, suppose you click and start dragging the prism. I would assume you want to change the coordinates of the lower-left corner to be the point on the XZ plane that would project to the current mouse coordinates, with possibly an offset because likely the user won't click on that one corner.

The best idea I can think of to get that would be to, before rendering the scene, render the XZ plane and call gluUnProject to return the point on it that would "map" to the mouse. Then change the coordinates of the prism, clear the buffers without calling glSwapBuffers and render the scene.

That sound like a reasonable plan? Obviously it would be better to do my own math, but if I can avoid reinventing the wheel, why not?

I'd love to hear comments, criticisms, other ideas etc if anyone has them!

daltxcoltsfan.tripod.com/OpenGL/OpenGL.htm

JanHH
07-19-2003, 08:51 PM
can't you simply catch the "mouse down" event and the "mouse up" event and compute the offset and the destination coordinate, and compute the resulting 3d coordinates? its fairly simple to compute the projection stuff yourself, all well known formulas and you know all the input parameters.

john
07-20-2003, 03:14 AM
Hello,

this sounds similar to work I have done and to a certain extent to the idea I'd like to implement but need to sort out the minimisation problem first (if, indeed, I can be bothered).

I'll describe the approach I did to see if it makes sense for in your case. The project I am working on involves stacking objects on top of each other. The metaphor I use is something like placing building blocks in the scene.

The engine always has some concept of the 'ground plane' somewhere in three-space (not necessarily the XZ plane---or, indeed, any axis-aligned plane) and the user is able to click on some point on the screen and drag out a new point. The idea is that the first mouse click is back-projected to intersect with the ground plane: this forms a 3D "anchor point" in world space and a 2D reference point on the plane. When the mouse is dragged, a new point is similarly back-projected to the ground plane. This new point forms a reference point and I compute a transformation wiht two degrees of freedom to map the anchor point to the origin of the object I want to place and the reference point to some arbitarily defined anchor point.

In a simple example, suppose I have the ground plane x-1=0 and I clicked an anchor point <1, 2, 3> (this pt satisfies the plane equation) and dragged a new reference point <1, 3, 3> for some geometry with a local origin <0, 0, 0> and handle <1, 0, 0> then the transformation I compute for this configuration is to map <0, 0, 0> to <1, 2, 3> *AND* map <1, 0, 0> to <1, 3, 3>... which would give me am effective transformation... well, it'd rotate 45 degrees around the object's y axis, a unit scale and a some other planar transformation to map the XZ plane to the x=1 plane.

Anyway. I do all that without rendering anything to the screen because its all just simple solving linear equations: you know the ray you've formed by back projecting a pixel in three space and you can easily compute the intersection of that ray with the plane equation by formulas available on the web, somewhere (like mathworld.wolframm.com). The only tricky aspect is computing the transformation along the plane, but if you keep your parameters simple enough then there WILL be a uniqye set of parameters that will exactly fit. You can't use all parameters; pure rotation about two axis, for example, won't span the entire space on the plane: you'd have to have one rotation and a scale or a translation to ensure that all points on the plane WILL have valid parameters, otherwise you'll need to do some minimisation stuff.

DalTXColtsFan
07-20-2003, 09:44 AM
Originally posted by JanHH:
can't you simply catch the "mouse down" event and the "mouse up" event and compute the offset and the destination coordinate, and compute the resulting 3d coordinates? its fairly simple to compute the projection stuff yourself, all well known formulas and you know all the input parameters.

Well, minor detail I think would be mousedown, mousemove *and* mouseup because I would want the object to move along with the mouse cursor - that's why I was saying that at any given moment I would want the object to be at the point on the XZ plane that maps to the mouse.

If I try to use formulas to figure out which point on the XZ plane maps to the current mouse XY coordinate, isn't that re-inventing the wheel? Is there any reason not to use gluUnProject?

I'll be honest, I haven't really started studying in detail exactly what the modelview and projection matrices hold, maybe if I looked into that I could figure it out.

DalTXColtsFan
07-20-2003, 09:49 AM
john, thanks for the detailed response, yeah I think you're saying exactly what I'm saying, I just hadn't really begun thinking about how to do it for an arbitrary plane.

I like what you pointed out with the "degrees of freedom" thing, because it's exactly what I was thinking at the beginning, you'd almost *have* to have some sort of restriction when dragging an object wouldn't you? I mean, when the user moves the mouse up and down, how do you know if it's forward and backward along Z or up and down along Y? You'd *have* to have something in there to govern where the object could go.

I think that other than, my question is the same one I had for the other guy who responded, and that's, first of all to be honest I haven't studied those 2 matrices in a lot of detail so maybe it'll make more sense when I do, the other, is there a reason to make your own formulas when gluUnProject will do the same thing?

What do you think?

Thanks a ton
Joe

john
07-21-2003, 03:35 AM
Howdy,

thats the rihgt idea about restricting geometry movements. You've only got two known parameters (the x and y of the mouse position on the screen) so you can only ever recover two 3D parameters from the transformation. THe other point about the transformation parameters you choose to find is that you need to make sure they span the space. for example, if you suppose that your geometry can't translate and scale and you only want to rotate aboutu two axis then you'll have a problem because not every point projected to a plane will generate valid rotation parameters. For example, if your geometry is in a cube bounded by +/-100, then no amount of rotation will get a vertex to map to 10000, for example. (But it could with a suitable scale or translation!)

I use my own formulas because its actually quite easy and convenient for me to do so, but there's nothig wrong with using gluUnproject if you know the depth of yoru pixel (with your rendering the XY plane idea, for example).

I'll show you my code to give you an example of how I do my back projection. Of course, there's a lot more code in the background to implement the Line3D and Matrix4 storage classes...

(This code is straight from my project, btw)



/* back projects image point v with projection*modelview matrix PM */
Line3D Geometry::backProject(const Point2D &amp;v, const Matrix4 &amp;PM)
{
Vector3D v3d=Vector3D(v.x(), v.y(), 0.0, 1.0);
Matrix4 PMinv=PM.inverse();
Point3D a=PMinv*v3d;
v3d.v[2]=1.0; // change the depth
Point3D b=PMinv*v3d;
return(Line3D(a, b));
}

Point3D GfxEng::groundPlaneReference(const Point2D mp, const Plane &amp;plane)
const
{
/* compute the intersection of the ray formed by back-projecting the mouse
pixel with the current working plane */

Line3D bp=Geometry::backProject(mp, user.getProjectionMatrix()*
user.getModelviewMatrix());
return(plane.intersect(bp));
}

Point3D Plane::intersect(const Line3D &amp;line) const
{
/* Paul Bourke (astronomy.swin.edu.au/~pbourke) is a legend! */

double u=(p[0]*line.A().x()+p[1]*line.A().y()+p[2]*line.A().z()+p[3])/
(p[0]*(line.A().x()-line.B().x())+p[1]*(line.A().y()-line.B().y())+
p[2]*(line.A().z()-line.B().z()));
return(line.parameter(u));
}

That computes the 3D intersection of the ray formed by back-projecting the point mp (bounded by +/-1) and intersected with some plane.

I hope this is of some guidance.

cheers
John

DalTXColtsFan
07-21-2003, 05:41 PM
Well John, first I gotta say again thanks for the detailed post, second, I think I'm going to have to start studying those matrices because I found a GAPING hole in my plan to just use the depth from the XZ plane!

Imagine if the object you're wanting to drag is 10 units tall, but the "camera" is just a little bit above the XZ plane - the XZ plane would only occupy a thin stripe in the middle of the screen, and the object could be so tall that if you click to drag from the top of it you could not ever touch the XZ plane and therefore have nothing to back project to!

So it seems that I have no choice but to look into those matrices!

Thanks again for the help, I'll disappear and look into those for awhile and see what I can figure out and I'll be back if I get stuck!

Thanks
Joe