Screen coordinates to planeTerrain world coordinates

I know this have already discussed but what I'm looking for is slightly different (no object picking).

What I just want to do is to know where on a plane I clicked.

My camera is in perspective mode and is always perpendicular and facing the plane. I just scroll up/down or left/right.

Maybe it's pretty easy (a few lines of code) but I can't figure out mathematics behind this since I'm just a beginner.

Hope it's a clear explanation  :expressionless:

Thanks in advance ! ! !

Hi orelero

If i understand Your case then You just have to compute the offset of Your cam to the origin of the plane.

Then You add the offset to Your cam's location up/down left/right and there You are.


edit: ah, no thats missing the part with the "where i clicked" sorry had overlooked that in the first pass :slight_smile:

yeah it's like a top view game where u can scroll the map (here it's only a plane) only in a horizontal way.

The camera has a constant altitude.

Let say I want to click somewhere on the plane to make a robot moving to his position. How can I get the world coordinates of this position ?

The best way is to use Camera.getWorldCoordinates with the Z argument set to the distance between the camera and the plane.

but when I'm doing this:

cam.getWorldCoordinates(screenCoords, altitude)

I get weird results: only the decimals are changed and if i scroll a bit and click at the same position on the plane, the coords are totally different  :?

That's why I think there is a easier way using mathematics to get these coordinates.

Well, since you are only scrolling, and have a fixed altitude, One very easy (and hacky) way of doing this without getting much into math would be to approximate it, knowing that it must be a linear function of the height, width and altitude (depth).

For instance, create a quad with the exact ratio of the camera view port, and then just adjust the altitude until it completely fills the view. Then you know the altitude at which your camera must be set to get the coordinates of all points in the quad… Then just readjust it to your camera height by simple multiplication of the ratio between the two.

The other option, if you want precise solutions, is to access the perspective transformation directly (i.e. you only need the wide angle and the height angle) Which should be something like 45deg and 35deg IFRC. And just do triangle proportions yourself

I tryed your second solution Duenez which gives simply:

public void onButton(int button, boolean pressed, int x, int y)
        if(button == 0 && pressed)
            System.out.println("zWorld="+ (x-display.getWidth()/2)*(1+2*cam.getLocation().y*FastMath.tan(FastMath.PI/4)/display.getWidth())+cam.getLocation().z);
            System.out.println("xWorld="+ (y-display.getHeight()/2)*(1+2*cam.getLocation().y*FastMath.tan(FastMath.PI/5.143f)/display.getHeight())+cam.getLocation().x);

I used 45 and 35 for width and height angles.
The plane is placed at the origin 0,0,0.

It doesn't work because the unit system for world coordinates seems really weird:
in my case, the terrain plane is 128x128 and I should see entirely with the cam knowing the viewport is 720x576 if the units were the same. But it's not the case.

Something I don't understand and can't figure it out alone  :'(.

Please help me. Thanks !!

Sorry, I had not have time to check this… I will tomorrow.

Hey Duenez ! In fact I just realized that there is a transformation of what the camera can see and what we can see so it fits the window's viewport whatever the resolution  :expressionless:

I think I should use the method with ray intersecting a plane (

ray.whereIntersectPlane(Plane p)

) or something like that.

finally it works :

public void onButton(int button, boolean pressed, int x, int y)
            Vector2f mouseScreenCoords = new Vector2f(x,y);
            Vector3f mouseWorldCoords = display.getWorldCoordinates(mouseScreenCoords, 0);
            Vector3f mouseWorldCoords2 = display.getWorldCoordinates(mouseScreenCoords, 1);
            Vector3f direction = mouseWorldCoords2.subtractLocal(mouseWorldCoords).normalizeLocal();
            Ray mouseRay = new Ray(mouseWorldCoords, direction);
            Plane p = new Plane();
            Triangle t = new Triangle(new Vector3f(0,0,0),new Vector3f(1,0,0),new Vector3f(0,0,1));
            Vector3f loc = new Vector3f();
            boolean intersection = mouseRay.intersectsWherePlane(p,loc);
            System.out.println("intersection?  "+intersection+" x="+loc.x+" y="+loc.y+" z="+loc.z);

But it's not accurate cause my terrain is 128x128 and when i click on the top right corner of it, I get x=126,.. and y=126,...

why can't you just use displaySystem's getPickRay method to make a Ray and use Spatial's findPick method to locate your intersection point?  (See also HelloMousePick and TestPick)

funny cause I just noticed there was such a method in DisplaySystem  :wink: I'm just pretty new at Jme