Convert RectTransform rect to screen space

I have a RectTransform that is the child of several other RectTransforms. Is there a way for me to convert the child RectTransform’s rect property (which is in the local space of the transform) into global screen space (essentially pixel coordinates relative to a corner of the screen)?

Edit: My Canvas is set to Screen Space - Camera and is rendered by the main camera.

I wanted to draw a bounding box of some UI elements when in editor, regardless of their orientation.

The easiest way I found that completely handles all cases of nesting, rotation, scaling, anchor offsets, etc. was to use [RectTransform.GetWorldCorners][1] and manually compute the Bounds:

private static Vector3[] WorldCorners = new Vector3[4];
public static Bounds GetRectTransformBounds(RectTransform transform)
{
    transform.GetWorldCorners(WorldCorners);
    Bounds bounds = new Bounds(WorldCorners[0], Vector3.zero);
    for(int i = 1; i < 4; ++i)
    {
        bounds.Encapsulate(WorldCorners*);*

}
return bounds;
}
----------
Since calls that require a Rect typically are defined as existing on the XY plane (such as [Gizmos.DrawGUITexture][2]), computing a rect from the bounds is trivial.
Here is an example:
private static Texture2D MakeTexture(float opacity)
{
Texture2D texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, true);
texture.SetPixel(0, 0, new Color(1, 0, 0, opacity));
texture.SetPixel(0, 1, new Color(0, 1, 0, opacity));
texture.SetPixel(1, 0, new Color(0, 0, 1, opacity));
texture.SetPixel(1, 1, new Color(1, 1, 1, opacity));
texture.Apply();
texture.filterMode = FilterMode.Point;
return texture;
}

public float opacity = 0.5f;
private Texture2D tex = null;

private void OnValidate() => tex = MakeTexture(opacity);
private void Awake() => tex = MakeTexture(opacity);

private void OnDrawGizmos()
{
Bounds bounds = GetRectTransformBounds(transform as RectTransform);
Rect screenRect = new Rect(bounds.min, bounds.size);
Gizmos.DrawGUITexture(screenRect, tex);
}
And the result:
![alt text][3]
[1]: Unity - Scripting API: RectTransform.GetWorldCorners
[2]: Unity - Scripting API: Gizmos.DrawGUITexture
[3]: https://i.imgur.com/dmCLPda.gif

Try this out:

    public static Rect RectTransformToScreenSpace(RectTransform transform)
    {
        Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
        return new Rect((Vector2)transform.position - (size * 0.5f), size);
    }

Although it’s been a while since this question was active, I’ve stumbled across it and came up with an extended solution.
Because I needed a similar function but the above solutions didn’t take non-default pivots on a RectTransform into account, I’ve picked up adamonline45’s solution and added a position shift by the transforms pivot multiplied by it’s screen size. The 1.0 - transform.pivot.y is done due to the flipped y-axis.

    public static Rect RectTransformToScreenSpace(RectTransform transform)
    {
        Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
        Rect rect = new Rect(transform.position.x, Screen.height - transform.position.y, size.x, size.y);
        rect.x -= (transform.pivot.x * size.x);
        rect.y -= ((1.0f - transform.pivot.y) * size.y);
        return rect;
    }

I’ve tested it with some GUI.Box calls in an OnGUI() method, which worked fine as it overdraw the UI button I used as RectTransform.

Here’s a slightly modified version of the above solution which also accounts for UI anchor positions (in case anyone else comes across this topic like I did):

public static Rect RectTransformToScreenSpace(RectTransform transform)
{
	Vector2 size= Vector2.Scale(transform.rect.size, transform.lossyScale);
	float x= transform.position.x + transform.anchoredPosition.x;
	float y= Screen.height - transform.position.y - transform.anchoredPosition.y;

	return new Rect(x, y, size.x, size.y);
}

Yet another answer taking pivot points into account. as neither the answer from @Tobias-Pott nor @IVxIV worked for me…

public static Rect RectTransformToScreenSpace(RectTransform transform)
{
    Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
    float x = transform.position.x - (transform.pivot.x * size.x);
    float y = transform.position.y - ((1.0f - transform.pivot.y) * size.y);
    return new Rect(x, y, size.x, size.y);
}

Screen mode and pivit indipendant. Working solution (c# 7.3)

/// <summary>
    /// Returns Left to right top to bottom screen position in rectTransform.
    /// </summary>
    /// <returns></returns>
    public static (bool positionIsInRect, Vector2 positionInRect) GetScreenPositionInRect(
        RectTransform rectTransform,
        Vector2 inputScreenPosition)
    {
        // top left corner
        var corners = new Vector3[4];
        rectTransform.GetWorldCorners(corners);
        var topLeft = corners[1];

        // rectTransform.position can be in world coordinate and in screen coordinates
        var canvas = rectTransform.GetComponentInParent<Canvas>();
        var topLeftScreen = canvas.renderMode == RenderMode.ScreenSpaceOverlay
            ? topLeft
            : canvas.worldCamera.WorldToScreenPoint(topLeft);

        // LeftRight TopBottom possition in
        var positionInRect = new Vector2(
            inputScreenPosition.x - topLeftScreen.x,
            Screen.height - (inputScreenPosition.y + (Screen.height - topLeftScreen.y)));

        // if out of rect return null
        if (positionInRect.x < 0 || positionInRect.x >= rectTransform.rect.width) return default;
        if (positionInRect.y < 0 || positionInRect.y >= rectTransform.rect.height) return default;

        return (true, positionInRect);
    }

Pity i spent all my day developing such an easy behaviour…

RectTransformUtility.ScreenPointToLocalPointInRectangle()
will work too, but without an example i was not able to understand this function :frowning:

After many hours, this is what worked for my case:

private static Rect GetScreenPositionFromRect(RectTransform rt, Camera camera)
        {
            // getting the world corners
            var corners = new Vector3[4];
            rt.GetWorldCorners(corners);
            
            // getting the screen corners
            for (var i = 0; i < corners.Length; i++)
                corners _= camera.WorldToScreenPoint(corners*);*_

// getting the top left position of the transform
var position = (Vector2) corners[1];
// inverting the y axis values, making the top left corner = 0.
position.y = Screen.height - position.y;
// calculate the siz, width and height, in pixle format
var size = corners[2] - corners[0];

return new Rect(position, size);
}

I had two challenges with @Malkyne’s answer (which could be my own doing):

  • I didn’t have a constructor for Rect which took two vectors
  • The position had to be converted to screen space (+y is down)

Here is what worked for me:

public static Rect RectTransformToScreenSpace( RectTransform transform )
{
    Vector2 size = Vector2.Scale( transform.rect.size, transform.lossyScale );
    return new Rect( transform.position.x, Screen.height - transform.position.y, size.x, size.y );
}

Otherwise, thanks, @Malkyne!

None of the answers here worked for me, and it keeps being first in my Google searches, so hopefully this will be helpful to some future similar soul. It works for my use case as far as I’ve tested it.

The returned Rect is in screen coordinates, which is to say 0,0 is at the top left corner and y+ is down.

    public static Rect RectTransformToScreenSpace(RectTransform transform)
    {
        Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);

        float newRectX = transform.position.x + (Screen.width / 2) - (size.x * (1 - transform.pivot.x));
        float newRectY = Mathf.Abs(transform.position.y - (Screen.height / 2)) - (size.y * (1 - transform.pivot.y));

        return new Rect(newRectX, newRectY, size.x, size.y);
    }

In 2018, What I have used is RectTransformUtility, by Unity Official Support.

RectTransform yourRectTransform = yourObject.getComponent<RectTransform>();
Canvas root = yourRectTransform.transform.transform.root.GetComponent<Canvas>();
Rect rect = RectTransformUtility.PixelAdjustRect(yourRectTransform, root);

That’s it.

Be Noticed: The origin is not what you thought (My guess is 0,0 in the center of screen), you might see the negative x and y, but Width and Height are simply correct in Screen Space.

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;
    }

You mean world space when you say global screen space .Change the render mode of canvas to world space first.