What is the proper use of Camera.WorldToScreenPoint()?

I have a function placing a box overlay over my other ships in the scene. The funny thing is when I call Camera.WorldtoScreenPoint() it fails to appear over the ships transform in all situations.

Presumably there should be no change in the overlay’s position relative to the ship its places over if the camera moves around in the scene. Yet that’s what happens.

Its a very frustrating problem.

Video ( no sound )

using UnityEngine;
using UnityEngine.UI;

public class Target : MonoBehaviour
{
    /// <summary>
    /// Designed to be attached to the target. Will display a box overlay on top of itself with a scaling target bubble lead on the players screen.
    /// </summary>

    public Image boxPrefab, leadPrefab; //Target box overlay
    Image box, lead;
    Camera cam;
    Canvas canV;
    MouseFlight flightScript;
    Vector3 screenCenter, worldPoint;
    public float placeDistance;

    FlightScript thisPreyFlier;

    void Start()
    {
        screenCenter = new Vector3( Screen.width / 2 ,Screen.height / 2, 0f );
        cam = GameObject.Find("MainCamera").GetComponent<Camera>();
        canV = GameObject.Find("Canvas").GetComponent<Canvas>();
        box = Instantiate(boxPrefab);
        lead = Instantiate(leadPrefab);
        box.transform.SetParent(canV.transform);
        lead.transform.SetParent(canV.transform);
        box.transform.localScale = Vector3.one;
        lead.transform.localScale = Vector3.one;
        thisPreyFlier = gameObject.GetComponent<FlightScript>();
    }

    private void OnEnable()
    {
        if(box != null && lead != null)
            setTargetActiveState(true);
    }

    public void update(MouseFlight predator) /*You [Unity board members] can ignore the calculations in this function. They are not the focus of the question, though something is definitely a miss with them. */
    {
        Vector3 vR = thisPreyFlier.Velocity - predator.Velocity;
        Vector3 sR = thisPreyFlier.transform.position - predator.transform.position;
        float tc = Mathf.Abs(sR.magnitude/ vR.magnitude);
        worldPoint = thisPreyFlier.gameObject.transform.position + (thisPreyFlier.Velocity * tc);
        box.rectTransform.localPosition = cam.WorldToScreenPoint(gameObject.transform.position) - screenCenter; /*THIS LINE is what I'm asking about. This should be simple. Give the function a worldspace position and it converts it to screen space. Subtract the screen's center to make things align, and then they box should be over the ship on the players screen. For some reason differing orientations cause the box to shift around. */
        lead.rectTransform.localPosition = cam.WorldToScreenPoint(worldPoint) - screenCenter;
        box.transform.rotation = canV.transform.rotation;
        lead.transform.rotation = canV.transform.rotation;
    }

    public void setTargetActiveState(bool b)
    {
        box.gameObject.SetActive(b);
        lead.gameObject.SetActive(b);
    }
}

This is what my scene set up looks like:

It probably has to do with Plane Distance as that is how far in front of the camera the UI elements are projected. Given the effect you’re going for you may have better luck with Screen Space Overlay mode.

Wham-o! Like magic! You were right! Thanks!

1 Like