iDevGames Forums
2D Click to 3D Point - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Game Programming Fundamentals (/forum-7.html)
+--- Thread: 2D Click to 3D Point (/thread-5457.html)



2D Click to 3D Point - Disparity - Jun 5, 2005 07:51 PM

How can I find the point on a plane that the user has clicked on? There's only one plane (the floor) in my particular example, but how hard would it be to do more?

I'm pretty sure "picking" is not what I want... and is the math required for the other method is beyond my abilities?

Advice?


2D Click to 3D Point - Shivers - Jun 5, 2005 07:54 PM

I'm not sure about the question but why not send a ray straight from the cursor to the plane and check for the point of intersection.


2D Click to 3D Point - longjumper - Jun 5, 2005 08:14 PM

Well, you could use picking. If you subdivided the floor into smaller quads, you could figure out which part of the floor was hit. Then it wouldn't be hard to do multiple planes either. You'd have each plane be made up of 20 quads, if you pick a piece 1-20 you're on plane 1, 21-41 you're on plane 2, etc. In fact, that'd probably the best way to do it.


2D Click to 3D Point - hangt5 - Jun 5, 2005 10:18 PM

I had to do this for my last couple of games, basicly you can either reverse engineer openGL matrix math, or use gluUnproject(), the later being MUCH easier (http://www.mevis.de/opengl/gluUnProject.html) If you set the winz parameter to 0 (for example if this was for mouse coordinates) It will return a ray from the camera through openGL space. Once you have the ray you do a little algebra. See this thread for how to find the intersection point of a ray and a plane. http://www.idevgames.com/forum/showthread.php?t=8784 The lasts two posts are what you want.


2D Click to 3D Point - Fenris - Jun 6, 2005 05:52 AM

Use gluUnproject and use in the current value for the z coordinate.


2D Click to 3D Point - Disparity - Jun 7, 2005 08:20 AM

Alright, thanks for the advice everyone. I got it to work, but it doesn't seem to be very accurate whenever the mouse is too far from the origin. The farther from the origin the more the more inaccurate the resulting point is. For example, when I click on (5,5,0) the resulting point is always further out, to say (5.5, 5.5, 0). And that gets worse as the mouse moves outwards... Any help with that?

And for some reason, using a winz of 1 worked, while 0 (and anything else for that matter) didn't. Perhaps this is part of the problem?

Here's the code:
Code:
GLdouble modelMatrix[16];
GLdouble projectMatrix[16];
GLint viewport[4];

NSPoint mouseLocation = [[self window] convertScreenToBase:[NSEvent mouseLocation]];
    
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectMatrix);
glGetIntegerv(GL_VIEWPORT, viewport);
gluUnProject(mouseLocation.x, mouseLocation.y, 1.0, modelMatrix, projectMatrix, viewport, &objSpaceCoords[0], &objSpaceCoords[1], &objSpaceCoords[2]);
    
_vector eye;
eye.x = 5.0;
eye.y = 5.0;
eye.z = 10.0;

_vector normal;
normal.x = 0.0;
normal.y = 0.0;
normal.z = 1.0;

_vector pointOnPlane;
pointOnPlane.x = pointOnPlane.y = pointOnPlane.z = 0.0;
    
_vector ray;
ray.x = objSpaceCoords[0];
ray.y = objSpaceCoords[1];
ray.z = objSpaceCoords[2];
    
double T;
T = vectorDotProduct(normal, vectorSubtract(pointOnPlane, eye)) / vectorDotProduct(normal, ray);
pointInPlane = vectorAdd(eye, vectorScale(ray, T));



2D Click to 3D Point - phydeaux - Jun 7, 2005 09:09 AM

You need to use the depth value of the pixel clicked (you can read it in) as the z value. If you are using a constant z value that is the same as trying to find the world-space coordinates of a plane of that z value in view space, which I don't think is what you want.

Reading in the depth value of a pixel is not always a good idea because it can stall the rendering pipeline, so you may just want to use a geometry library to do the intersection of a ray and a plane.


2D Click to 3D Point - Fenris - Jun 7, 2005 09:14 AM

You can avoid stalling the pipeline if you read the depth value just after you swap the buffers. That way you're always one frame behind with the mouse coordinate, but it shouldn't make much of a difference unless you're rewriting Duck Hunt. (Hey, I wonder if I was inspired by the above post's avatar?)


2D Click to 3D Point - phydeaux - Jun 7, 2005 10:29 AM

Fenris Wrote:(Hey, I wonder if I was inspired by the above post's avatar?)
Duck Hunt and OpenGL? Nintendo should make Duck Hunt 3D.

(Okay, I googled, and at least someone did)


2D Click to 3D Point - Disparity - Jun 7, 2005 11:54 AM

Well, it now works perfectly as I'm using two different depths (1 and 0) to create a ray from the camera, and then intersect it with my plane. I found some code on another thread... but I can't find the link... Annoyed
Code:
gluUnProject(mouseLocation.x, mouseLocation.y, 0.0, modelMatrix, projectMatrix, viewport, &x, &y, &z);
ray.origin.x = x;
ray.origin.y = y;
ray.origin.z = z;

gluUnProject(mouseLocation.x, mouseLocation.y, 1.0, modelMatrix, projectMatrix, viewport, &x, &y, &z);
ray.direction.x = x - ray.origin.x;
ray.direction.y = y - ray.origin.y;
ray.direction.z = z - ray.origin.z;

ray.direction = vectorNormalize(ray.direction);
hangt5, did you not have the same problem w/ only one depth?


2D Click to 3D Point - hangt5 - Jun 8, 2005 01:31 PM

I got the unprojected point with a winZ of 0.
I created a vector from that point to my camera position.
its a WHOLE lot easier then reading in the depth value of a pixel.

Heres some code.
Code:
    double xPos = mLocation.x;
    double yPos = mLocation.y;
    
    double zPos = 0.0f;
        
    GLdouble fx, fy, fz;
    
    gluUnProject(xPos,yPos,zPos,modelViewMatrix, projectionMatrix, viewportMatrix, &fx,  &fy, &fz);
    
    LCPoint *unProject = [LCPoint set:fx:fy:fz];
    
    ray = [unProject minus:cameraPosition];
    [ray normalize];
    
    //T = [planeNormal.(pointOnPlane - rayOrigin)]/planeNormal.rayDirection;
    //pointInPlane = rayOrigin + (rayDirection * T);

    LCPoint *p1;
    
    float dot1, dot2;
    
    LCPoint *pointOnPlane = [LCPoint set:0:0:0];
    LCPoint *rayOrigin = [LCPoint set:cameraPosition];
    LCPoint *planeNormal = [LCPoint set:0:1:0];
    LCPoint *rayDirection = [LCPoint set:ray];
    
    p1 = [pointOnPlane minus:rayOrigin];
    
    dot1 = ([planeNormal x] * [p1 x]) + ([planeNormal y] * [p1 y]) + ([planeNormal z] * [p1 z]);
    dot2 = ([planeNormal x] * [rayDirection x]) + ([planeNormal y] * [rayDirection y]) + ([planeNormal z] * [rayDirection z]);
    
    float t = dot1/dot2;
    
    [rayDirection multiply:t];
    
    LCPoint *pointInPlane = [cameraPosition plus:rayDirection];

Make sure to populate your projectionmatrix/viewportMatrix/modelViewMatrix after gluLookAt. Not before.


2D Click to 3D Point - Disparity - Jun 26, 2005 01:33 AM

How would one find the point on a heightfield (w/ triangles)? I'm sure I'll be able to figure out the ray-triangle intersection, but how would I efficiently handle this?

Would a quadtree work here?


2D Click to 3D Point - Disparity - Jun 26, 2005 01:39 AM

Hrm... I think I'll answer my own question. I'll do a quadtree, and then do some ray-cube intersections to find out which triangles I need to check against. Then I'll only take the closer triangle (if more than one is in the path of the ray).


2D Click to 3D Point - kberg - Jun 26, 2005 02:34 PM

Use a 2D DDA algorithm:

http://www.kenmusgrave.com/grid_tracing.ps (postscript file)


2D Click to 3D Point - Trodmi - Jul 11, 2008 08:30 AM

I think this will help:
http://www.og.delcode.com/OpenGL_draw_plane_3d.zip