Search Unity

Rect.width returning confusing values in certain render modes

Discussion in 'UGUI & TextMesh Pro' started by Natey, Jul 9, 2017.

  1. Natey

    Natey

    Joined:
    Oct 10, 2014
    Posts:
    26
    Hi yall!

    So, for finding the width of a rect transform, I know that there are a few ways to do it. One way is to use rectTransform.GetWorldCorners. Another way is to use rectTransform.rect.width. For me, I can get both solutions working in Screenspace-Overlay. But in Screenspace-Camera and World Space, I can only seem to use GetWorldCorners to find the width. This is because rectTransform.rect.width is returning confusing, stretched out values in Screenspace-Camera, and Worldspace.

    Here's an example of some test code that works perfectly in Screenspace-Overlay but not in Screenspace-Camera:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class WidthTest : MonoBehaviour {
    7.    
    8.     //Small green marker indicating tansformToMeasure's center
    9.     public RectTransform center;
    10.  
    11.     //Small red marker indicating the x value of tansformToMeasure's left side
    12.     public RectTransform left;
    13.  
    14.     //Small blue marker indicating the x value of tansformToMeasure's right side  
    15.     public RectTransform right;
    16.  
    17.     //The transform we are measuring
    18.     public RectTransform transformToMeasure;
    19.  
    20.     void Start () {
    21.         center.position = transformToMeasure.position;
    22.  
    23.         left.position = transformToMeasure.position;
    24.         left.position -= new Vector3(transformToMeasure.rect.width / 2.0f, 0, 0);
    25.  
    26.         right.position = transformToMeasure.position;
    27.         right.position += new Vector3(transformToMeasure.rect.width / 2.0f, 0, 0);
    28.     }
    29. }
    This code take three small markers, and places them in the left, right, and center of the RectTransform called transformToMeasure. As mentioned it works perfectly in Screenspace - Overlay:


    And here it is not working in Screenspace - Camera:


    So ultimately my question is this: Am I missing something here, or does rect.width and rect.height just return bunk values in Screenspace-Camera and Worldspace? I know that I can just get the width and high easily using GetWorldCorners, but it would seem odd to me if rect.width and rect.height are still accessible in Screenspace-Camera but simply do not work properly. Also worth noting, I tried to multiply the width values times canvas.scaleFactor as someone mentioned somewhere, and that didn't seem to work--at least not the way I was doing it.

    Thanks for reading! Have a good one!
     
    Harinezumi likes this.
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    OK, the route of your issue in discovering the width when using either different canvas types or even different canvas scalar types is the anchors.

    The anchors behave differently based upon how the canvas, pivot and anchors are defined for a UI object.

    You should be able to use the SizeDelta property of the RectTransform to get an accurate screenspace width. GetWorldCorners will give you the rendered worldspace width of a recttransform which is likely different to the screenspace size.

    Hope that's not too confusing. Problem is it will change based on your setup, so use the pattern that fits in your setup and don't change if you can help it.
     
  3. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi @Natey - I think @SimonDarksideJ is right...

    Your solution is not going very far with these points he mentioned in mind...

    Try rotating your RectTransform, scaling it, changing its pivot location, splitting its anchor points, changing Canvas scaling mode or Canvas type... most of these will break your placement calculations.

    I think the rect calculations are working just fine, but many times they don't just make sense when only thinking layout element boxes and their placement visually and ignoring the actual hierarchy of scaling and pivots etc.

    But instead, if you just do this with the GetWorldCoordinates you mentioned:

    Code (csharp):
    1.  
    2. Vector3[] c = new Vector3[4];
    3. tm.GetWorldCorners(c);
    4. left.position = (c[1]-c[0]) * 0.5f + c[0];
    5. right.position = (c[2]-c[3]) * 0.5f + c[3];
    6.  
    ...With this, try scaling, rotating and changing RT pivot position... also, try scaling Canvas, changing canvas type and scaling mode and so on.
     
    Harinezumi and SimonDarksideJ like this.
  4. Natey

    Natey

    Joined:
    Oct 10, 2014
    Posts:
    26
    Thanks for helping me with this yall! Both of you provided some valuable insights to me. If anyone has anything to add on this, feel free, but I'm happy with the answers here! Have a good one!
     
  5. Natey

    Natey

    Joined:
    Oct 10, 2014
    Posts:
    26
    Just in case anyone digs this up later, I found a slightly more direct answer to my original problem. Which is to use localPosition instead of position in my original script. That way you can use rect.width or the world corner stuff, depending on what you feel like.
     
  6. zyzyx

    zyzyx

    Joined:
    Jul 9, 2012
    Posts:
    227
    To add to that: when using Rect.width etc. of a RectTransform you want to multiply the value by the parent canvas' scaleFactor to get the correct dimensions.
    This depends of course on how you set up your CanvasScaler.
     
    Natey and eses like this.
  7. thenash654

    thenash654

    Joined:
    Jan 28, 2016
    Posts:
    4
    I have found that GetWorldCorners is correct during Update() for me, but fails in other functions such as Start(). The values I get between the two functions are different for some reason. Perhaps that could be the case for you?