Extract Model Coordinate at mouse location

Hello, I have a JOGL 3D terrain in a Jpanel which is centered inside a JFrame. How would I extract the model coordinate of the point that my mouse is hovering over? I think I have to extract my mouse screen coordinate, the modelview matrix, and do a multiplication, but I am unsure of the math. Furthermore, as I indicated above, my JPanel is centered in the JFrame, so does that mean I have to add an offset to my mouse coordinates?

I look forward to your responses. Meanwhile I will check the red book.

Thanks
Devang

If what your’e trying to get is to convert the mouse screen coordinates to the world coordinates then try the codes below. You will need a 3D math library for the Vector3f stuff. You can find one at http://www.objectclub.jp/download/files/vecmath/vecmath1.2-1.14.tar.gz

Let me know if it works for you.

/**

  • Transform screen pixel coordinates to 3D world coordinates
    */
    public float[] screenToWorld(GL gl, GLU glu, int sx, int sy)
    {
    StringBuffer result = new StringBuffer(32);
    double[] p0 = new double[]{0f, 0f, 0f};
    double[] p1 = new double[]{0f, 0f, 0f};
    float[] p = new float[]{0f, 0f, 0f};
double[] objX = new double[]{-1};
double[] objY = new double[]{-1};
double[] objZ = new double[]{-1};
int realy = viewport[3] - sy;

/* Get world coordinates of mouse position at near plane */
glu.gluUnProject(sx, realy, 0, model, proj, viewport, objX, objY, objZ);
p0[0] = objX[0];
p0[1] = objY[0];
p0[2] = objZ[0];

/* Get world coordinates of mouse position at far plane */
glu.gluUnProject(sx, realy, 1, model, proj, viewport, objX, objY, objZ);
p1[0] = objX[0];
p1[1] = objY[0];
p1[2] = objZ[0];

 /* Intersect a ray with this plane, outputing the 3D intersection point */
 Vector3f rayStart = new Vector3f((float)p0[0], (float)p0[1], (float)p0[2]);
 Vector3f rayDirection = new Vector3f((float)(p0[0] - p1[0]),
                                      (float)(p0[1] - p1[1]),
                                      (float)(p0[2] - p1[2]));
 Vector3f normal = NORMAL(new Vector3f((float)west, 1f, south),
                          new Vector3f((float)west, 1f, (float)north),
                          new Vector3f((float)east, 1f, (float)north));
 Vector3f origin = new Vector3f();
 float denom = rayDirection.dot(normal);
 if (denom != 0.0f)
 {
   Vector3f tmpDir = new Vector3f();
   tmpDir.sub(origin, rayStart);
   float t = tmpDir.dot(normal) / denom;
   /* Find intersection point */
   Vector3f tmpPt = new Vector3f();
   tmpPt.set(rayDirection);
   tmpPt.scale(t);
   tmpPt.add(rayStart);
   tmpPt.get(p);
   /* As the northings are negative, trip the sign before using. */
   p[2] = Math.abs(p[2]);
 }

//System.out.println(“SCREEN TO WORLD - WORLD COORDINATES(x,y,z)=”+p[0]+","+p[1]+","+p[2]);
return p;
}

/**
*
*/
private Vector3f NORMAL(Vector3f p0, Vector3f p1, Vector3f p2)
{
Vector3f n = new Vector3f();
n.x = (p1.y - p0.y) * (p2.z - p0.z) - (p1.z - p0.z) * (p2.y - p0.y);
n.y = (p1.z - p0.z) * (p2.x - p0.x) - (p1.x - p0.x) * (p2.z - p0.z);
n.z = (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);
return n;
}

Hi,

you should read the depth buffer to find the z coordinate of your click…

like this :
gl.glReadPixels ( clickX, (int)winY, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, winZ );

In my app I avoided doing manual intersection calculations by using selection mode to determine the possible intersections. Works like a charm for me…

Just to clarify: reading from the depth buffer will not, AFAICS, return the z-coordinate of a click in your scene. The depth buffer contains values that depend on the near and far clipping planes, and are also in a quadratic scale. You would have to manually adjust the returned value to get a more meaningfull depth reading.

Well i thought, and it works fine for my applications, that querying the z-coordinate to pass to gluUnproject this way was the right method…
But I may have not expressed myself well, the value returned by glReadPixels will be between 0.0 and 1.0 and gluUnproject will … well … “unproject” the screen coordinates enhanced with z-buffer value into world coordinates.

I may be wrong, but I believe (and hope) it works!

As far as I know, Bleb is correct.The non-linear transformation bit of the z coordinates is part of the projection transformation matrix. gluUnproject uses the inverse of the projection and modelview matrix to get you back your original model coordinates.

Ok, thanks for the explaination, I think I understand …
It’s strange that I hadn’t had some problems of accuracy…

Doh, I meant to say you (turquoise3232) were right, which is kind of what my little explanation was meant to show. ::slight_smile: Sorry for the mixup.
As bleb said a perspective projection transformation matrix performs a non-linear transformation on the z coordinates, but this isn’t really an issue at all. A valid perspective projection transformation matrix is inversible so you can always go back to the untransformed coordinate.
If your intrested in the math, a matrix is inversible iff it’s determinant is not zero. In the case of a perspective projection matrix the determinant can be calculated as

((-2 * zfront) / (xright - xleft)) * ((-2 * zfront) / (ytop - ybottom)) * ((-2 * zfront * zback) / (zfront - zback))

Where all the variable are the parameters you would pass to glFrustum. This formula is only zero if zfront or zback is 0, which aren’t valid values. In other words the matrix should always be inversible.
Here’s some more info on perspective projection, matrix inverse and matrix determinants.
And now, back to the dull day job… :slight_smile:

Well, thanks, i’m relieved :stuck_out_tongue:
Since my math lessons are quite far behind me the non-linear part had afraid me a little… And i was too lazy to check.

[quote]And now, back to the dull day job…
[/quote]
I’m sure my boss will agree on that!

sorry to bring back such an old topic but i found the code above most interesting as well as being a potential solution to the problem, i’m current having, got most of the code but wasn’t sure what the variables north, east, south and west were above any help on them would be appreciated.

thanks

The west, east, north and south vlaues define the extent in world coordinates.