CanvasScaler current scale?

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?

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.

1 Like

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.

1 Like

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.

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?

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 :wink:

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 : Unity - Manual: Execution Order of Event Functions

5 Likes

Even in Update I receiving scaleFactor = 1;
You should calculate it:
float canvasScale = Screen.width / canvas.GetComponent().referenceResolution.x;

3 Likes

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.

1 Like

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: UGUI世界坐标转屏幕坐标_ugui 将场景坐标转换成屏幕坐标-CSDN博客

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:

    public static Vector2 WordToScenePoint (Vector3 wordPosition)
    {
        CanvasScaler canvasScaler = GameObject.Find ("Canvas").gameObject.GetComponent<CanvasScaler> ();

        float referenceWidth = canvasScaler.referenceResolution.x;

        float referenceHeight = canvasScaler.referenceResolution.y;

        float match = canvasScaler.matchWidthOrHeight;

        float offect = (Screen.width / referenceWidth) * (1 - match) + (Screen.height / referenceHeight) * match;

        Vector2 a = RectTransformUtility.WorldToScreenPoint (Camera.main, wordPosition);

        return new Vector2 (a.x / offect, a.y / offect);
    }

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-Technologies/ui/src/a3f89d5f7d145e4b6fa11cf9f2de768fea2c500f/UnityEngine.UI/UI/Core/Layout/CanvasScaler.cs?at=2017.3&fileviewer=file-view-default)

Line 166 to 178: (some is deleted for convinence)

case ScreenMatchMode.MatchWidthOrHeight:
{
// We take the log of the relative width and height before taking the average.
// Then we transform it back in the original space.
// the reason to transform in and out of logarithmic space is to have better behavior.
// If one axis has twice resolution and the other has half, it should even out if widthOrHeight value is at 0.5.
// In normal space the average would be (0.5 + 2) / 2 = 1.25
// In logarithmic space the average is (-1 + 1) / 2 = 0
float logWidth = Mathf.Log(screenSize.x / m_ReferenceResolution.x, kLogBase);
float logHeight = Mathf.Log(screenSize.y / m_ReferenceResolution.y, kLogBase);
float logWeightedAverage = Mathf.Lerp(logWidth, logHeight, m_MatchWidthOrHeight);
scaleFactor = Mathf.Pow(kLogBase, logWeightedAverage);
break;
}

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.

3 Likes

Hey guys!
Had the same issue yesterday. After then implementing it like psioniccat suggested i spend some more thoughts last night and recognized that the Canvas itself has a scaleFactor as well Unity - Scripting API: Canvas.scaleFactor this one is working as intended. So you can use this instead.
Best Daniel

8 Likes

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

1 Like

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.

1 Like

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:

Vector2 canvasSize = canvas.pixelRect.size;
Vector2 scaledSize = ((RectTransform)canvas.transform).sizeDelta;
Vector2 proportion = scaledSize / canvasSize;
Vector2 mousePointing = mousePos * proportion;

Or, what I found later to be:

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

3 Likes

Only applies with renderMode is Screen Space. Does not work for most of the cases.

3 Likes

Nice! It works.

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.

1 Like

Where is Unity’s guy reply to this??!!

You can access the source code for the Canvas Scaler here.

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!