Search Unity

CanvasScaler current scale?

Discussion in 'UGUI & TextMesh Pro' started by FamerJoe, Dec 11, 2014.

  1. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    It seems like this would be obvious, but I can't seem to find out how to get this number.

    For instance, if the reference resolution is 1920x1080, and the current resolution is 960x540, then the current scale of the UI would be 0.5. Is there any way to grab this number from the CanvasScaler component?
     
  2. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    After the canvas has been scaled you should be able to just read it back from the scaleFactor on the canvas as the canvas scaler just controls this value.
     
    EirikWahl likes this.
  3. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    That's what I would have thought, but for my project, it's 1.00 all the time, regardless of resolution, full screen or windowed. I don't understand, because the UI is scaling accordingly.
     
    DragonCoder likes this.
  4. cdytoby

    cdytoby

    Joined:
    Nov 19, 2014
    Posts:
    181
    I have the exact same issue, how to solve it?

    I want to get the unscaled width and height of the canvas.
    RectTransform.rect is useless, always returns 0.
    I can get size with Canvas.pixelRect, but this size is scaled.
    and the scale from the RectTransform is always 0, and the scale from Canvas and CanvasScaler is always 1.
     
  5. Draudastic

    Draudastic

    Joined:
    Oct 28, 2016
    Posts:
    5
    I can confirm this.
    Never thought this simple value could be the source of my problems...
    I mean this value can be calculated easily, but why is this variable there?
     
  6. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668
    After ‘googling’ for an answer, it brought me here -I understand this is an old post. I thought I would share what I realized. Hope it saves some brain cells ;)

    Tim-C from Unity is correct. If you do canvas.scaleFactor it actually does work. However, if you are assigning this value to something at, OnEnable(), there's a very high chance that you will get the wrong scale. (usually scale of 1)

    I think the reason for this is the execution order. See the link below. GUI items are one of the last to get called.
    If you do canvas.scaleFactor at Start() (you will definitely see it at Update()) you will actually see the correct value (same as what you see grayed out in the Rect Transform).

    Hope this helps.


    Execution Order LINK : https://docs.unity3d.com/460/Documentation/Manual/ExecutionOrder.html
     
  7. Aca

    Aca

    Joined:
    Apr 22, 2014
    Posts:
    10
    Even in Update I receiving scaleFactor = 1;
    You should calculate it:
    float canvasScale = Screen.width / canvas.GetComponent<CanvasScaler>().referenceResolution.x;
     
    avacio, seancheno and seblaf1 like this.
  8. cjuillard

    cjuillard

    Joined:
    Aug 2, 2013
    Posts:
    6
    canvas.scaleFactor hasn't worked for me either, regardless of when I try and access it - I'm assuming this is just a Unity bug. I'm on 2018.1.0f2.

    Aca's solution only works in some cases. Found this Stackoverflow solution that's a little more general where they suggest using the CanvasScaler's transform.localScale. Working well for me.
     
    Akashelia likes this.
  9. psioniccat

    psioniccat

    Joined:
    Jul 12, 2018
    Posts:
    2
    I don't know if I'm too late for replying this. I've also met this problem.

    Conclusion first:
    a) canvasScaler.scaleFactor is always 1 because I have never set its value (its default value is 1).
    b) I have never set its value because my canvasScaler is working in "Scale With Screen Size" mode instead of "Constant Pixel Size" mode.
    c) And CanvasScaler doesn't update the value of scaleFactor in "Scale With Screen Size" mode.
    d) Just manually calculate scale factor in the same algorithm can solve this.

    I did try to get canvas.scaleFactor and it's always 1. But I found this: https://blog.csdn.net/a8856621/article/details/50144869

    This article is written in Chinese, but you don't need to fully understand that. Just look at the code. Some variables are even not been used, and the most important line is too long for me, so I made a little modification:

    Code (CSharp):
    1.  
    2.     public static Vector2 WordToScenePoint (Vector3 wordPosition)
    3.     {
    4.         CanvasScaler canvasScaler = GameObject.Find ("Canvas").gameObject.GetComponent<CanvasScaler> ();
    5.  
    6.         float referenceWidth = canvasScaler.referenceResolution.x;
    7.  
    8.         float referenceHeight = canvasScaler.referenceResolution.y;
    9.  
    10.         float match = canvasScaler.matchWidthOrHeight;
    11.  
    12.         float offect = (Screen.width / referenceWidth) * (1 - match) + (Screen.height / referenceHeight) * match;
    13.  
    14.         Vector2 a = RectTransformUtility.WorldToScreenPoint (Camera.main, wordPosition);
    15.  
    16.         return new Vector2 (a.x / offect, a.y / offect);
    17.     }
    18.  
    The most interesting part is defenitely this offect. It is similar to what we really want: canvas.scaleFactor.

    Finally I found the reference source of CanvasScaler on 2017.3 (https://bitbucket.org/Unity-Technol...ler.cs?at=2017.3&fileviewer=file-view-default)

    Line 166 to 178: (some <space> is deleted for convinence)
    Code (CSharp):
    1.  
    2. case ScreenMatchMode.MatchWidthOrHeight:
    3. {
    4. // We take the log of the relative width and height before taking the average.
    5. // Then we transform it back in the original space.
    6. // the reason to transform in and out of logarithmic space is to have better behavior.
    7. // If one axis has twice resolution and the other has half, it should even out if widthOrHeight value is at 0.5.
    8. // In normal space the average would be (0.5 + 2) / 2 = 1.25
    9. // In logarithmic space the average is (-1 + 1) / 2 = 0
    10. float logWidth = Mathf.Log(screenSize.x / m_ReferenceResolution.x, kLogBase);
    11. float logHeight = Mathf.Log(screenSize.y / m_ReferenceResolution.y, kLogBase);
    12. float logWeightedAverage = Mathf.Lerp(logWidth, logHeight, m_MatchWidthOrHeight);
    13. scaleFactor = Mathf.Pow(kLogBase, logWeightedAverage);
    14. break;
    15. }
    16.  
    The result is named as "scaleFactor" and looks exactly what we want. But it's not been kept inside of canvasScaler because there is another float named scaleFactor on Line 163. My math is not that good to fully explain that, but I believe that the calculation of offect is a short version of these when matchWidthOrHeight is 0.5.

    The algorithm for offect is working fine in my project. (2018.1.7f1). It should work on 2018.2, I suppose.
     
    Last edited: Aug 9, 2018
    azevedco, Claytonious and gaolei_nls like this.
  10. CxydaInno

    CxydaInno

    Joined:
    Sep 5, 2017
    Posts:
    14
    Last edited: Nov 2, 2018
  11. Srithej

    Srithej

    Joined:
    Nov 23, 2017
    Posts:
    1
    Hey guys if you want to modify the value "Match"(according to the unity inspector) when you enable "uiscalemode" = "Scale with Screen Size" and "screenmatchmode" = "MatchWidthOrHeight" so now you wanna modify the value match..
    According to the Scripting API,
    https://docs.unity3d.com/ScriptReference/UI.CanvasScaler-matchWidthOrHeight.html
    MatchWidthOrHeight is a float value which you can modify or get returned..
    Try this piece of code:

    public class abc : MonoBehaviour
    {
    void Start()
    {
    CanvasScaler c = GetComponent<UnityEngine.UI.CanvasScaler>();
    c.uiScaleMode = UnityEngine.UI.CanvasScaler.ScaleMode.ScaleWithScreenSize;
    c.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
    c.matchWidthOrHeight = 1f;
    Debug.Log(c.matchWidthOrHeight);
    }
    }

    Attach this code to the Canvas. You get the CanvasScaler component and store in in a variable "c" of type CanvasScaler. And then modify the values depending on your needs
    I hope I answered the query.
    Thank You
     
    Daveheart likes this.
  12. arnaldoGaroto

    arnaldoGaroto

    Joined:
    Feb 3, 2013
    Posts:
    22
    like CxydaInno says, the Canvas itself has a scaleFactor and is slightly different from the 'offect' value I was getting with that code (in my case, the cavas one was the one I needed).
    Also if you look at the sizeDelta of the Canvas RectTransform, it is set to the resolution resulting from applying the matchWidthOrHeight setting to the reference resolution.
     
    Last edited: Mar 11, 2020
    EZaca likes this.
  13. EZaca

    EZaca

    Joined:
    Dec 9, 2017
    Posts:
    32
    Thank you so much, @arnaldoGaroto! I was looking for transforming from screen point to canvas point, and I was able to do it with sizeDelta, where I get:

    Code (CSharp):
    1. Vector2 canvasSize = canvas.pixelRect.size;
    2. Vector2 scaledSize = ((RectTransform)canvas.transform).sizeDelta;
    3. Vector2 proportion = scaledSize / canvasSize;
    4. Vector2 mousePointing = mousePos * proportion;
    Or, what I found later to be:
    Code (CSharp):
    1. Vector2 proportion = Vector2.one / canvas.transform.localScale;
    It works even if you mess with reference resolution or the "match" option. "scaleFactor" always returns 1f for me. Not sure if it was that you were looking for six years ago ^^' haha
     
    OwnDemise and Patrick7L like this.
  14. NeverTrustShadows

    NeverTrustShadows

    Joined:
    Mar 15, 2020
    Posts:
    15
    Only applies with renderMode is Screen Space. Does not work for most of the cases.
     
    plamaliy, Akashelia and CxydaInno like this.
  15. Yiming075

    Yiming075

    Joined:
    Mar 24, 2017
    Posts:
    33
    Nice! It works.
     
  16. michaelday008

    michaelday008

    Joined:
    Mar 29, 2019
    Posts:
    135
    I noticed that when the Canvas Scaler has scaled itself, it affects its own RectTransform scale. In the picture below I had my app in focused (not maximized) mode in the editor, and the RectTransform scale of the canvas was set to 0.55625.
    upload_2022-11-6_12-2-3.png
     
    blahnumbers likes this.
  17. ahmed_ameen2

    ahmed_ameen2

    Joined:
    Jul 3, 2012
    Posts:
    5
    Where is Unity's guy reply to this??!!
     
  18. jadvrodrigues

    jadvrodrigues

    Joined:
    Feb 25, 2020
    Posts:
    12
    You can access the source code for the Canvas Scaler here.
     
  19. Daveheart

    Daveheart

    Joined:
    Mar 31, 2023
    Posts:
    5
    Just wanted to thank you for this.

    I wanted to support the Pixel Fold phone with my app, and make use of the extra space provided by the wider screen.
    My detection was spot on, but the problem I encountered was my "MatchWidthOrHeight" had always been on Width.

    On the Pixel Fold, in portrait mode with the screen open, this would cause the UI to be heavily zoomed in where you couldn't see it all.
    Naturally, just switching it to Height wouldn't work for most of the phones on the market so I needed this to be dynamic based on my Globals.isFold variable.

    Your code was perfect for letting me set this. Just wanted to thank you!