Getting World Coordinates of a UI-Rect Transform in 3D

Hi all,

I want to get the world position of a bar in a 2d barchart that is on a canvas in world space. The bar itself is a 2d Image sprite that is transformed using rect transform. Additionally, it is part of a horizontal layout grid.

I tried to get the positions of the bar using:

bar.gameObject.transform.position; //the position of the Image-UI element, where bar is the Image sprite

this however gives me a weird position somewhere in world space (I don’t even know where this position comes from). I attached two images to illustrate the issue:


Here is one bar. I would like to get the position of the origin you can see in the image

Here I’ve drawn a line from the table you can see in the lower right corner to the transform position. As you can see the line goes way over the Image.

I was curious about this myself so I did some tinkering.

The magic sauce I think you’re missing is probably two things:

  • a setting in the CanvasScaler object on your Canvas. It maps the pixels in the canvas to the world coordinates.
  • setting the size of your Canvas RectTransform to be comparable to your world stuff.

I set my pixel scaler to 800 pixels per world unit, just to get the text reasonable scale-wise.

I set my canvas to 10 wide 7 high to match a plane in my 3D scene.

See the attached unitypackage. Press run and it puts the two ends of a line renderer at the canvas text object and the cube. Look at the settings I used in the canvas scaler and the canvas rect.

That was done in Unity 5.6.2 and uses the new .numPositions property of the line renderer. If you’re in much-earlier Unity there is a different property to set the vert count, I forget what. You can probably just delete that line because I put two verts in the LineRenderer in the scene.

3372939–264519–ForumWorldCanvases.unitypackage (5.34 KB)

Hey,

thanks for the answer! Your example actually lead me to digging a bit further:

The issue is in fact the horizontal layout group! I modified your code with me example and it lead me to this:


Without Horizontal Layout Group the line (the pink line) goes correctly to the origin of the bar (now simply a child of the canvas hanging somewhere in the air ;))


With Horizontal Layout Group the line is still at the old origin of the bar.

Can anyone explain how this works?

Did you know that the Unity UI code is open-source? You can get it here:

https://bitbucket.org/Unity-Technologies/ui

The relevant class is tiny, so not sure what is happening in your case. I’ll copy/paste the class here:

namespace UnityEngine.UI
{
    [AddComponentMenu("Layout/Horizontal Layout Group", 150)]
    public class HorizontalLayoutGroup : HorizontalOrVerticalLayoutGroup
    {
        protected HorizontalLayoutGroup()
        {}
        public override void CalculateLayoutInputHorizontal()
        {
            base.CalculateLayoutInputHorizontal();
            CalcAlongAxis(0, false);
        }
        public override void CalculateLayoutInputVertical()
        {
            CalcAlongAxis(1, false);
        }
        public override void SetLayoutHorizontal()
        {
            SetChildrenAlongAxis(0, false);
        }
        public override void SetLayoutVertical()
        {
            SetChildrenAlongAxis(1, false);
        }
    }
}