A Solution To Unity’s Camera.WorldToScreenPoint Causing UI Elements To Display When Object Is Behind The Camera

If you’ve ever worked with Camera.WorldToScreenPoint to get object positions on the screen from their world space positions, and then displayed some sort of UI element on it, you may have noticed that when your camera faces away from the objects, you still get your UI element displaying on the screen. This is due to Camera.WorldToScreenPoint using an infinite line through the object and through the screen.

If you search on Google or the Unity Forums/Answers, you’ll get three solutions for this:

  • Use Camera.WorldToScreenPoint’s “z” value to determine when the object has passed the screen’s plane, and then disable the UI element.
  • Use Vector3.Dot with the camera’s transform.forward direction with the direction towards the object to find out if the object has passed the screen’s plane and if so, disable the UI element.
  • Use a Rect of (0, 0, Screen.width, Screen.height) to determine if it contains the object’s screen point, and disable the UI element.

These solutions may or may not work well depending on the type of UI element you’re using. Since I’m using a selection box in my prototype as you can see above, which is drawn by getting the corners of an invisible collider box around the spacecraft, I get a lot of weird issues depending on the angle of the camera and how close it is to the object. Using the solutions above solves one problem but leaves others.

After much trial and error, I found a solution after getting a better understanding of how Camera.WorldToScreenPoint gives screen coordinates when the object is behind the camera. I’m posting it here because I haven’t seen anyone post anything similar online.

Here is the code:

(Hover the mouse over the code for a toolbar to appear in the top right. You can copy the code, or open it in a new window using the toolbar).

*Disclaimer* I’m not an advanced programmer, but still wanted to share what I found to help others stuck with the same problem. There may be a better way of doing this, and if you know of one, please share it in the comments below. Please also share if you find a way to optimize this code.

The heart of the solution is in the block:

You can see the reasoning behind the solution in the comments.

To observe how this works, have another scene view open while the Unity editor is in Play mode. Make it 2D and display the UI Canvas within the scene view. If you’re using a selection or highlight indicator of some sort, you can see how it stretches and where it’s located, especially when the camera is looking away from the object.

All the best!

 

Leave a Comment