1
\$\begingroup\$

I was wondering how I could achieve an offscreen indicator effect that helps direct the player to the next waypoint. My game is 3D, most solutions I have found are for 2D games (i.e Asteroids).

See this example of Warzone. I have highlighted the parts that I am interested in creating.

enter image description here

The engine I am using has an API call to convert from world to screen position. This only returns the X and Y components though. Do I need the Z component to achieve what I am after?

From what I understand so far:

  • Check if target is off screen
  • If off screen convert 3D world position to 2D screen position (only X and Y components)

The Math for snapping the 2D UI icon to the side of the screen so it moves around is where I get lost. I read something about slope intercept is something that can solve this but am not sure how to apply it to my problem.

If it helps I will be writing this in JavaScript, however, I'm not after a language specific solution, am really interested in understanding the Math so I can write it myself for any language.

\$\endgroup\$
1
\$\begingroup\$

I assume that this API method you're talking about projects the point onto camera's near plane. That would mean that you get point on screen so that X=-1 is left border, X=1 is right border, Y=-1 is bottom and Y=1 is top. If that is the case, then you have to clip this X, Y point to your camera boundaries, which should be in normalized coordinates as [-1, 1], something like icon.X = max(-1, min(X, 1)). That should do the trick. You do that in both dimensions X and Y.

Additional check for world point being "behind" player could be good to manually snap the icon to the bottom of the screen: if waypoint projected onto player's forward vector points back AKA dot(forward, wapointPos-playerPos) < 0, then icon.Y := 0.

Another way (assuming you already have a code that checks if world point is in camera's cone of vision) is comparing the sign of dot product between the waypoint vector and camera's right. If dot(right, waypoint) > 0 then icon is on the right border, otherwise on the left. This generalizes to 3 dimensions by repeating this check for Y. You just have to think in planes camera.forward, camera.right for positioning on left/right border and in camera.forward, camera.up for positioning on the top/bottom border.

If you lack the code to check if point is inside camera's cone of vision, then you would have to do something like this:

  1. project the waypoint onto camera's near plane
  2. clip the point to camera's boundaries.

You can use intercept theorem to project the point onto camera's near plane (check out the picture). Additional work is required to translate the projected vector to normalized coordinates of near plane (for example calculate using FOV and projecting on camera's right vector)

// waypoint vector
let W = (waypointPos - playerPos);
// x like in picture
let x = (near * W.length() / dot(W, forward))
// waypoint projected onto near plane (forward is camera's forward vector)
let W' = W * x / W.length() ; // watch out for overflow
// check if camera waypoint is behind neaer plane of camera
let glueBottom = dot(forward, W') < near;
// translate W' to screen coordinates [-1, 1]
// ...

Key aspect is projecting vectors onto right planes - but planes are always determined by two other vectors, so you just use them to project correctly.

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.