Converting UI RectTransform to Screen Pixel and vice-versa

I am creating an Image that showed when user touch the screen and automatically changing it position based on current touch position. my Canvas Render mode are Screen Space Overlay.

also I am creating an Image with fixed position, and when user touch the screen, a script will determine is touch are touching this Image and resulting the touch coordinate relative to Image position in screen Pixel

so my question is how to convert screen pixel Coordinate to UI RectTransform and convert it back to screen Pixel Coordinate?

notes : I have searching about RectTransformUtility but i don’t know what the function used for and how I use it.

You’re in luck, I’m procrastinating from stuff I should be doing and this is just the sort of thing that can make it seem like I’m doing something important!

which is why I’ve spent half an hour trying to get this working. Can’t say I can guarantee what the results are but I got it outputting a result.

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

public class RectUtil : MonoBehaviour {

	public Camera MainCam;
	public RectTransform myRectT;
	private Vector3 result;


	//225,96,40
	//ScreenPointToWorldPointInRectangle(rect: RectTransform, screenPoint: Vector2, cam: Camera, worldPoint: Vector3): bool;

	// Use this for initialization
	void Start () {
		Vector2 myV2 = new Vector2(0,24);
		Debug.Log (RectTransformUtility.ScreenPointToWorldPointInRectangle(myRectT,
		                                                                   myV2,
		                                                                   MainCam,
		                                                                   out result));
		Debug.Log (result);
	}
}

Although the help says that it returns coordinates in world space, they are actually in screen space. So the solution is simple:

public Rect GetScreenCoordinates(RectTransform uiElement)
{
  var worldCorners = new Vector3[4];
  uiElement.GetWorldCorners(worldCorners);
  var result = new Rect(
                worldCorners[0].x,
                worldCorners[0].y,
                worldCorners[2].x - worldCorners[0].x,
                worldCorners[2].y - worldCorners[0].y);
  return result;
}

expending on mrpmorris solution:

 public Rect GetScreenCoordinatesOfCorners(RectTransform uiElement)
 {
        var worldCorners = new Vector3[4];
        uiElement.GetWorldCorners(worldCorners);
        var result = new Rect(
                      worldCorners[0].x,
                      worldCorners[0].y,
                      worldCorners[2].x - worldCorners[0].x,
                      worldCorners[2].y - worldCorners[0].y);
        return result;
  }

 public Vector2 GetPixelPositionOfRect(RectTransform uiElement)
 {
        Rect screenRect = GetScreenCoordinatesOfCorners(uiElement);
       
        return new Vector2(screenRect.center.x, screenRect.center.y);
  }

The general logic to convert world position (Vector3) to screen position or anchored position (Vector2) is:

  • Get the worldPoint by
    gameObject.transform.position
  • From worldPoint, get the screenPoint
    by
    RectTransformUtility.WorldToScreenPoint
  • From screenPoint, translate it to
    localPointInRectangle (anchoredPoint)
    by
    RectTransformUtility.ScreenPointToLocalPointInRectangle

The code function:

public static Vector2 WorldPointToLocalPointInRectangle(Vector3 worldPoint,
            Camera camera, Canvas canvas, RectTransform parentRect) {
            var screenPoint = camera.WorldToScreenPoint(worldPoint);

            // Translate screen point to local point of a parent rect transform
            // If canvas render mode is ScreenSpace-Overlay, camera param should be null
            // Ref: https://docs.unity3d.com/ScriptReference/RectTransformUtility.ScreenPointToLocalPointInRectangle.html
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                parentRect, screenPoint,
                canvas.renderMode == RenderMode.ScreenSpaceCamera ? canvas.worldCamera : null,
                out var result);
            return result;
        }

I spent several hours and finally found this workaround:

Even when gameObject has a RectTransform, it also has a transform component that is invisible in the inspector, but still accessible through a script:

// RECT TRANSFORM TO SCREEN SPACE
    public  Vector2 LocalPositionToScreenPosition(RectTransform _rectTransform)
    {
        Vector2 screenCenter = new Vector2(Screen.currentResolution.width / 2, 
                                           Screen.currentResolution.height / 2);

        Vector2 output = (Vector2)cam.WorldToScreenPoint(_rectTransform.position) - screenCenter;

        Debug.Log(output);
        return output;
    }