- Home /
Sprite scaling in different aspect ratios
This has been asked a lot and I've truly did my search, experimented with orthographic camera, etc. The math in "correct" answers in other posts is correct, but it just doesn't work for me for some reason. I have a sprite 119x119 pixels. My computer is 1366x768 and the screen aspect ratio is 16:9. i use this line for scaling:
this. sprite.transform.localScale = new Vector3(Screen.width/1366f, Screen.height/768f, 1);
It scales the sprite correctly in all resolutions in on my computer. Yet I tried running it on aspect ratios like 5:3, etc. and it just looks stretched on either axis.
Now, maybe there's something I'm doing wrong? All I want is to keep the sprites with the same aspect ratio, not squared in any way on every resolution. C#.
Thank you for any help.


Hi, you don't need to scale a sprite for different screen aspect ratio, you just have to display it at different positions on the screen. You may want to scale the sprite to fit into a smaller/bigger resolution though, it's a different problem. You can read this from Unity's new UI system that is valid for any 2D sprite: http://docs.unity3d.com/460/Documentation/$$anonymous$$anual/HOWTO-UI$$anonymous$$ultiResolution.html (check how the "ReferenceResolution" component works, there are tutorial videos too here: http://unity3d.com/learn/tutorials/modules/beginner/ui but I can't remember which one talks about this component)
You would have to scale the sprites if the pixel aspect ratio was different on different screens but this is very rare with recent devices: check https://en.wikipedia.org/wiki/Pixel_aspect_ratio
What do you mean by different positions? Say it was in the middle of the screen, the resolution change would stretch it in the x axis? In the 1366x768 it looks perfect, but on 640x480 it is stretched. The position doesn't really make any difference, at least as far as I know. What I want is for it to be the same on every resolution. The new UI system wouldn't work as of now because it's for unity 4.6, which is beta and should only be used for testing.
Again, for the sake of clearity (I'm sorry if you misunderstood): I'm making a menu and the components cannot be stretched in any way, their size has to remain constant on every device.
I'm scaling it on different resolutions, but if the screen aspect ratio changes, the codes have to change as well, and I don't know how.
Answer by _dns_ · Nov 01, 2014 at 05:17 PM
Ok, the comment was not clear, I go for a longer answer (not enough space for a comment)
The documentation on the 4.6 is interesting because it explains how Unity 4.6+ handles different resolutions. There are examples of different cases and one must be what you want to do. It's interesting even if you don't use 4.6+.
If you want your UI to be the same on every resolutions and screen ratio without stretching, there are 2 different things to do: positioning and scaling/resolution.
Positioning: Imagine 2 screen size (x*y) 100x100 and 200x100. One is ratio 1:1, the other 2:1, note that they have the same pixel ratio of 1:1 = square pixels like all devices nowadays. If you have a 10x10 sprite to display on the upper left corner, you'll want to display it at 0,0 in both cases with the original 10x10 size. If it's in the upper right corner, it have to be displayed at 90,0 in the first screen and 190,0 in the second screen.
To compute this, the best is to use percentage (the Anchors in Unity 4.6). Say, the sprite is at the upper right corner when x = 90%. Then, 100*90% = 90, 200*90% = 180 and it will work for any resolution. That's a way to solve some cases. You will then need to define that the sprite's origin is at n % from the screen origin, or, that the sprite's right border is at 5% of the screen's right border, or, at 5% of the right border of a container (like a window or group of UI elements). That way, you can handle different screen size and ratio. It's not easy to cover all cases, that's why Unity 4.6 took long time to do I guess :-) (check the new RectTransform component)
Scaling: Now, in the previous example, the 10x10 sprite would be ok in both 100x100 and 200x100 screens, it doesn't need to be scaled. If we introduce a new 500x400 resolution, then the 10x10 sprite may become too small. You can manage this with a reference resolution. Say, your 10x10 sprite is perfect for 100x100 resolution, then, you can scale it according to the X resolution: 500 / 100 = 5. Then, the 10x10 sprite becomes 50x50. You can also choose the Y axis to scale it: 400/100 = 4: the sprite will be 40x40. You can also choose a mix of both X & Y ratio, most of the time the X ratio gives the best results.
With both positioning and scaling, you can achieve a UI that matches all screen ratio and resolutions, but that's not a simple task. If you can use the 4.6+ you will save time (and even if it's still in beta state, it's quite stable and should be released soon)
The other problems you'll have with different resolutions is that a sprite scaled 4x is not as nice as a not scaled one, and that a sprite scaled 0.25x becomes even more unreadable. You may then need different source images. Font is also a problem as the font size must be chosen according to resolution too (same concept as the sprite's scaling)
Well, that's not a simple problem. Unity 4.6 helps a lot, or check the asset store for solutions for pre 4.6 Unity versions.
I thank you enormously, everything you say is logical and the math is right. Downloading 4.6 will take me all the way until the morning, so for tonight I'll tackle the problem without it. Hmm... if I use something like:
sprite.transform.localScale = new Vector3(Screen.width/1366f, Screen.width/1366f, 1);
then the sprite look good in the editor when I change aspect ratios, yet, when I choose 640x480 res - it is stretched. Now, my physical screen aspect ratio is 1.5, but this resolution is 1.(3), I suppose that means the x is stretched to fill the screen and leave no black lines on the sides.
Yet if I use:
sprite.transform.localScale = new Vector3(Screen.width/1366f, Screen.width/768f, 1);
The sprite doesn't stretch in any way on my computers' screen, but if the aspect ratio changes, be it in the editor or on another computer I'm testing, the sprite is stretched. $$anonymous$$aybe I'm dense and am missing something, I just don't know how to go about this problem, how to take all the values and make something out of them. The logic, however, seems right.
Thank you again, I value any help I can get at this point :3
It only dawned on me now that the math and scaling using proportions of the x axis is correct, but it's my screen which stretches the 1.3 aspect ratio screen to fit the 1.5 one. I could enforce the aspect ratio and add black pillars on the sides, but maybe there's a way to go around it?
Your scaling formula is nearly correct. If the scale 1.0 is considered "perfect" for the 1366 resolution, you can scale it to other resolutions with Screen.Width/1366f. The thing is that to keep the aspect ratio, you must use this number for X and Y scaling. That's what I was talking about in the "scaling" part. You can use either width/1366 or height/768 or a combination of both (width/1366*0.7 + height/768*0.3) but you must use the same ratio for X and Y because all resolutions have the same square pixel ratio (no width/768).
Now, if your video card stretches the image to fit it in your screen when in fullscreen+lower than no$$anonymous$$al resolution, your pixel ratio will be changed. I don't think there is a way to detect this, the only solution would be to ask the user what is the no$$anonymous$$al resolution and compute a pixel ratio from this.
Then, for example, if the no$$anonymous$$al resolution is 1366x768 and the new fullscreen resolution is 640x480. The size of 1 pixel in X will be 1366/640=2.13. The size of 1 pixel in Y will be 768/480 = 1.6. Then, the ratio you have to apply is 2.13/1.6=1.33. Then, you have to use values that are 1.33 bigger in X than in Y (or 1/1.33=0.75 times smaller in Y).
As you base the resolution scale on X, better apply the ratio in Y. So you should scale by (width/1366f) in X and by (width/1366f)*0.75 in Y (width, not height here). Doing so you should keep the sprite ratio. You'll need to apply some ratio to positions too. I didn't check this with code, only pen+paper so I hope it works ;-)
It still somewhat distorts, I'm yet to make out a single scaling formula for this (What a feat that would be!). Thank you for bearing with me, I'll try some more to make the math work. I'm afraid it is way more complicated than I'm aware of.
Your answer