WorldToScreenPoint with Screen Space - Camera | Scale Issue?

So I have been trying to get points of 4 spheres that are in my scene to world space screen coordinates. My canvas render is set to Camera and NOT screen space overlay for a reason. When I switch to overlay it works because the scale of the rect is 1:1 not so the points are being scaled accordingly to fit inside the Screen Space - Camera Rect. How do I get the world positions of the spheres to the Screen Space - Camera canvas?

Screen shots below

Thanks!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class OrbController : MonoBehaviour
{

    public GameObject dropZone;

    Vector3 orginalOrbPos;
    Vector3 currentOrbPos;

    GameObject orb;

    LineRenderer lineRend;
    Vector2 mousePos;
    Vector3 screenCenter;

    // Start is called before the first frame update
    void Start()
    {
        screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
        print(screenCenter + " Screen width = " + Screen.width + " Screen Height = " + Screen.height);
        orb = this.transform.GetChild(0).gameObject;
        orginalOrbPos = this.transform.position;
        //lineRend = this.gameObject.AddComponent<LineRenderer>();
        //print(Camera.main.transform.GetChild(0).GetComponent<RectTransform>());
    }

    // Update is called once per frame
    void Update()
    {
        currentOrbPos = orb.transform.localPosition;
        this.GetComponent<SphereCollider>().center = currentOrbPos;
        //Debug.DrawLine(orb.transform.position, dropZone.transform.position, Color.blue, .1f);
        Debug.DrawLine(Camera.main.WorldToScreenPoint(orb.transform.position), dropZone.transform.position, Color.blue, .1f);
    }

    private void OnMouseDrag()
    {
        mousePos = Input.mousePosition;
        orb.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x,mousePos.y, Camera.main.transform.GetChild(0).GetComponent<Canvas>().planeDistance));
    }

}

1 Like

Once you have your screen position you could try using ScreenPointToLocalPointInRectangle which will take it from the screen position to your canvas position. Is that what you’re trying to do? As you mentioned, you wouldn’t need to do this in ‘overlay’ mode. Here’s what the docs say on that:

“The cam parameter should be the camera associated with the screen point. For a RectTransform in a Canvas set to Screen Space - Overlay mode, the cam parameter should be null.”

So when you’re not using overlay mode you can pass the RectTransform of your canvas to that function along with your screen point.

4 Likes

Hello, I have the same problem but I don’t seem to be able to solve it.

I have 4 cameras (split screen), each one of them taking up a fourth of the screen. Each camera has it’s own Canvas with Screen Space - Camera mode on. I have some world objects that I want each canvas to track independently.

The problem is that this Items appear so small that are imposible to see or appear too far away from the camera. Here is my code if anyone wishes to help me (I’ve been days trying to achieve this):

        //This code is inside the object that I want to be tracked. myCamera is the camera of the canvas.
        Vector3 screenPoint = myCamera.WorldToScreenPoint(myObjectTransform.position);
        Vector2 result;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent.GetComponent<RectTransform>(), screenPoint, myCamera, out result);
        transform.position = result;
5 Likes

encounter the same problem, solved by code below, not sure if it is the best solution, but it works for me
transform is the GameObject in scene, component Transform
mCanvas is UI canvas, component RectTransform
mCamera is camera used for scene

                    // convert screen coords
                    Vector2 adjustedPosition = mCamera.WorldToScreenPoint(transform.position);

                    adjustedPosition.x *= mCanvas.rect.width / (float)mCamera.pixelWidth;
                    adjustedPosition.y *= mCanvas.rect.height / (float)mCamera.pixelHeight;

                    // set it
                    mAnchorInUi.anchoredPosition = adjustedPosition - mCanvas.sizeDelta / 2f;
17 Likes

Thumbs up to the solutionis from @Yuanzezhong … Nothing else here on elsewhere worked, and tbh I have no idea why his solution did either lol. The sizeDelta piece is a magic wand afaik.

That’s a funny way of describing a magic wand.

1 Like

You just saved me

I used @Rayeloy 's code with just a tiny change. I assigned it to anchoredPosition instead and works like a charm with Screen Space - Camera.

1 Like

@Yuanzezhong thanks for your code, it finally worked for me!

Same here. What a life saver after milling about searching for a solution. One day I hope to answer people’s own questions.

1 Like
// Returns a normalized [0,1] position counted from camera bottom left
public static Vector2 GetRelativePosOfWorldPoint(Vector3 worldPoint, Camera camera) {
    Vector3 screenPoint = camera.WorldToScreenPoint(worldPoint);
    return new Vector2(screenPoint.x / camera.pixelWidth, screenPoint.y / camera.pixelHeight);
}

// Use it like this:
Vector2 canvasSize = theCanvasImRenderingOn.rect.size;
Vector2 relativePos = GetRelativePosOfWorldPoint(myWorldObject.transform.position, theCameraIAmLookingThrough);
theRectTransformIWantToPosition.anchorMin = theRectTransformIWantToPosition.anchorMax = Vector2.zero; // set bottom left anchor
theRectTransformIWantToPosition.anchoredPosition = relativePos * canvasSize;
1 Like

@Yuanzezhong worked for me, thanks!

@Yuanzezhong thanks you so much!

Please use the Like button to show your appreciation so as not to necro the thread.

Thanks.

1 Like

Necroposting even though there’s a post immediately before it stating the same.

Thread Closed.

1 Like