Converting between screen coordinates and scene/world coordinates

Started by
4 comments, last by mrgnpz 8 years, 8 months ago
Hello!

I am trying to learn OpenGL by coding a game for Android, but I have found myself in a pickle.

The game so far is a ship (a cube travelling along the Y axis), and I want it to shoot bullets (smaller cubes for now, for the sake of simplicity) towards the part of the screen that I touch. The Y coordinate of the ship is continously increasing due to it's movement and the camera is following it, using Matrix.setLookAtM, making the ship appear stationary.

Now for the question! Let us say I click on a part of the screen and assume Android spits the coordinates 100, 85 at me. How do I turn these coordinates into an angle relative to the ship (this is important)? By means of basic trigonometry, I could find the angle from the center of the ship to the point I touched on the screen. Although since I do not know the screen coordinate for the center of my ship (I only know it's coordinates in the world), I have come to a halt.

I would be grateful if anyone could point me in the right direction.
Advertisement

If you wanted an angle, you'd use arc tangent of your difference vector to find this. So, you'd do something like this:


Vector2 playerShipPosition; // x, y position of your ship
Vector2 touchPosition; // x, y position of where your finger touched the screen
Vector2 diff = touchPosition - playerShipPosition; // difference vector
float angle = atan2f(-diff.y, diff.x); // find the angle in radians as +/- PI

I wrote the code above in C++ as I haven't touched Java in a while. Java does have a built-in math function called atan2f though.

The variables: playerShipPosition and touchPosition, are your known variables that you've described above. The key is to find the difference in these two positions. Always subtract the destination point from the start point, otherwise your vector will face in the opposite direction. Once you have it, we use 'diff' vector's x and y components in atan2f(). This will give you the angle.

I'm making a few assumptions here:

1) This is a essentially a 2D game

If the game is in 3D, I'll need to know more information to give you a better answer that'll work in your game.

2) World-space units are measured in screen pixels

If you're working off of a world-space unit/screen pixels ratio, then you just need to make sure both playerShipPosition and touchPosition are in the same coordinate space. For example, if your ship, projectiles, and other scene elements would be in world units, and the pixel/unit ratio is 10 pixels per world-space unit. playerShipPosition is in world-space units, and Android's going to return your touch's position to screen coordinates. So, touchPosition would be Android's screen coordinates divided by 10. This gives you the touchPosition in world-space units. Again, assuming 2D here.

3) The positive y-axis of your world-space coordinate system is downward

If your ship's world-space coordinates are working off of a typical cartesian plane where the y-axis is upward, then diff.y won't be negative when you pass it into atan2f() as the 1st parameter. You will, however, have to add additional logic to convert the touch coordinates provided by Android to world-space because its positive y-axis is downward.

I have read your reply several times, but I still can not grasp the solution. The game is 2.5D, kinda. It's 3D graphics but top-down (looking down on the XY plane). Every entity lies in Z=0 so far. I simply can not understand how the two coordinate systems work together. The screen on Android gives me coordinates ranging from (0,0) in the top left corner to (width, heigh [of the viewport]) in the bottom right. I'm familiar with the math used here, but I don't understand how the ship and the point of the screen that I touch even lies in the same coordinate system. Suppose I want to shoot a bullet from the ship to the point of the screen that I desire. I press coordinate (100, 85) on the screen while the ship is at (0, 1500, 0). The ship only moves along the Y axis so far, increasing as the ship moves upwards. This gives us a diff vector of (100, 85) - (0, 1500) = (100, 85) + (0, -1500) = (100 + 0, 85 + (-)1500) = (100, -1415). Arctan of this is -176 degrees. -176 degrees is clearly not in the upper left corner where the screen coordinates (100, 85) reside. Either I'm misinterpreting you, or I haven't really understood the problem. Thanks.
Somehow my line breaks got lost when posting, and I can't edit the post. Sorry about that.

I don't understand how the ship and the point of the screen that I touch even lies in the same coordinate system

Transforming the ship's in-game world 3d-coordinates with a 'ModeViewProjection' matrix gives you the center of the ship in screen 2d-coordinates (in OpenGL screen coordinates are floats from 0 to 1, with Y axis inverted). You can then convert 0-1 coords to 0-width and 0-height, respectively, with a simple relation equation. That said, do you know, how to transform the coordinates with a modelviewprojection matrix? It's just matrix multiplication of the original model matrix of the ship by the view-projection matrix of the camera. Are you familiar with matrix multiplication?

Y axis flipped?

Android touch positions:

- relative to the top-left corner

- increase towards the bottom-right corner

OpenGL positions:

- relative to the bottom-left corner / or the center (it depends)

- increase to towards the top-right corner

This topic is closed to new replies.

Advertisement