I am writing a 2D game where my game world has x axis running left to right, y axis running top to bottom, and z axis out of the screen:
Whilst my game world is top-down, the game is rendered on a slight tilt:
I'm working on projecting from world space to screen space, and vice-versa. I have the former working as follows:
var viewport = new Viewport(0, 0, this.ScreenWidth, this.ScreenHeight);
var screenPoint = viewport.Project(worldPoint.NegateY(), this.ProjectionMatrix, this.ViewMatrix, this.WorldMatrix);
The NegateY()
extension method does exactly what it sounds like, since XNA's y axis runs bottom to top instead of top to bottom. The screenshot above shows this all working. Basically, I have a bunch of points in 3D space that I then render in screen space. I can modify camera properties in real time and see it animate to the new position. Obviously my actual game will use sprites rather than points and the camera position will be fixed, but I'm just trying to get all the math in place before getting to that.
Now, I am trying to convert back the other way. That is, given an x and y point in screen space above, determine the corresponding point in world space. So if I point the cursor at, say, the bottom-left of the green trapezoid, I want to get a world space reading of (0, 480). The z coordinate is irrelevant. Or, rather, the z coordinate will always be zero when mapping back to world space. Essentially, I want to implement this method signature:
public Vector2 ScreenPointToWorld(Vector2 point)
I've tried several things to get this working but am just having no luck. My latest thinking is that I need to call Viewport.Unproject
twice with differing near/far z values, calculate the resultant Ray
, normalize it, then calculate the intersection of the Ray
with a Plane
that basically represents ground-level of my world. However, I got stuck on the last step and wasn't sure whether I was over-complicating things.
Can anyone point me in the right direction on how to achieve this?