Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question WorldToScreenPoint in 3D appearing behind camera?

Discussion in 'UGUI & TextMesh Pro' started by Razputin, Jun 25, 2023.

  1. Razputin

    Razputin

    Joined:
    Mar 31, 2013
    Posts:
    349


    Hi, so I have the following wip script.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class EyeIcon : MonoBehaviour
    4. {
    5.  
    6.     public Transform target;
    7.     public RectTransform pointerRectTransform;
    8.  
    9.     private void Update()
    10.     {
    11.         bool visible = target.GetComponent<Renderer>().isVisible;
    12.         Vector3 pos = Camera.main.WorldToScreenPoint(target.position);
    13.         if (visible)
    14.         {
    15.             pointerRectTransform.position = new Vector3(pos.x, pos.y, 0);
    16.         }
    17.         else
    18.         {
    19.             pointerRectTransform.position = new Vector3(Mathf.Clamp(pos.x, 0,Screen.width - 100), Mathf.Clamp(pos.y, 0, Screen.height - 100), 0);
    20.         }
    21.     }
    22. }
    I want to move an icon over a target when it's visible and when it's not visible, move it to the nearest edge of the screen. However because I'm in 3D the worldtoscreenpoint seems to render the icon in the center of the screen when the target is behind the camera as the positional value is flipping back over to the start.

    Any thoughts on how I should go about handling this situation? I know how to determine if the object is behind the camera, but not exactly what to do with the UI at that point to prevent it from rendering in the wrong location.

    Thanks!
     
  2. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    996
    It all depends on what's the behavior you want when the target is behind the camera. A couple of ideas:
    • Make the arrow to simply disappear if the target is outside the camera view
    • Find the nearest edge on the screen and make the arrow point there
     
  3. Razputin

    Razputin

    Joined:
    Mar 31, 2013
    Posts:
    349
    Here is what I came up with. It does feel a little janky still so would love some feedback, as it's definitely not going to the "Closest" edge now.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class EyeIcon : MonoBehaviour
    4. {
    5.  
    6.     public Transform target;
    7.     public RectTransform pointerRectTransform;
    8.     public float border = 200;
    9.  
    10.     private void Update()
    11.     {
    12.         Vector3 pos = Camera.main.WorldToScreenPoint(target.position);
    13.         Vector3 dir = target.transform.position - Camera.main.transform.position;
    14.         float dot = Vector3.Dot(dir, Camera.main.transform.forward);
    15.         bool visible = (pos.x > 0 && pos.x <= Screen.width) && (pos.y > 0 && pos.y <= Screen.height) && dot > 0;
    16.         if (visible)
    17.         {
    18.             pointerRectTransform.position = new Vector3(pos.x, pos.y, 0);
    19.         }
    20.         else
    21.         {
    22.             if (dot < 0)
    23.             {
    24.                 pos.x = -pos.x;
    25.                 pos.y = -pos.y;
    26.             }
    27.             pointerRectTransform.position = new Vector3(Mathf.Clamp(pos.x, border, Screen.width - border), Mathf.Clamp(pos.y, border, Screen.height - border), 0);
    28.         }
    29.     }
    30. }
     
    Last edited: Jun 28, 2023
  4. Razputin

    Razputin

    Joined:
    Mar 31, 2013
    Posts:
    349
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,349