Controlling Aspect Ratio in Unity

Games made with Unity allow users to pick a screen resolution on startup through Unity's Display Resolution Dialog. While it's possible to disable this feature and force a game to use a particular resolution, it's generally not a good idea to deny users the ability to set the game's resolution to whatever they think is best. Such flexibility comes at a price, however, and one of the costs is the loss of control over the game window's aspect ratio.

Differences in aspect ratio aren't necessarily a problem, but I think it's generally a good idea to keep things as consistent as possible regardless of the system on which a game is running. For the camera, such consistency ensures that what you see during development and testing is also what players see once your game is released: Objects visible from a particular vantage point will be visible on all systems, and those that aren't visible will likewise remain out of view. A consistent view across systems means the context is the same for all players, with no player seeing more of the environment or the objects within it than intended by the game's designer.

While Unity's game editor allows developers to choose between a number of aspect ratios while developing a game, there's currently no way to specify a particular aspect ratio when a game is run outside of Unity's development environment. There is, however, a way to do this with a bit of extra effort. What follows, then, is a tutorial on how to guarantee the use a particular aspect ratio regardless of the game's resolution.

The first step is to create a camera script to adjust the camera's viewport according to the game window's current size and the desired aspect ratio. The script is created by choosing Assets -> Create and the desired script type from the editor's menu, after which the code to set the aspect ratio is added to the script's Start() function so that it's executed during the camera's initialization step. Here's some C# code that does just that:

// Use this for initialization
void Start ()
{
// set the desired aspect ratio (the values in this example are
// hard-coded for 16:9, but you could make them into public
// variables instead so you can set them at design time)
float targetaspect = 16.0f / 9.0f;

// determine the game window's current aspect ratio
float windowaspect = (float)Screen.width / (float)Screen.height;

// current viewport height should be scaled by this amount
float scaleheight = windowaspect / targetaspect;

// obtain camera component so we can modify its viewport
Camera camera = GetComponent<Camera>();

// if scaled height is less than current height, add letterbox
if (scaleheight < 1.0f)
{
Rect rect = camera.rect;

rect.width = 1.0f;
rect.height = scaleheight;
rect.x = 0;
rect.y = (1.0f - scaleheight) / 2.0f;

camera.rect = rect;
}
else // add pillarbox
{
float scalewidth = 1.0f / scaleheight;

Rect rect = camera.rect;

rect.width = scalewidth;
rect.height = 1.0f;
rect.x = (1.0f - scalewidth) / 2.0f;
rect.y = 0;

camera.rect = rect;
}
}

Once you've saved your new camera script, add the script to the camera by dragging the script from the Project window onto the camera's listing in the Hierarchy window. Now when you run your game the camera's viewport will be scaled and positioned to match the desired aspect ratio*.

Now the next step is to add a second camera to render the "black bar" region of the screen. While you can choose to render whatever the second camera is pointed at, in most cases you'll want to set the camera to render only a flat color such as black. To do this:
  1. Create the camera by choosing GameObject -> Create Other -> Camera from the editor's menu.
  2. Set the camera's depth value to -2 so it's rendered underneath the main camera (whose depth value defaults to -1).
  3. To set the black bar region to a solid color, set the camera's Clear Flags to "Solid Color", set the Culling Mask to "Nothing", and finally the Background to the desired color.
That's all you need to do. Now your game will run with the desired aspect ratio regardless of the user's choice of resolution.



* When running your game from within Unity's editor, be sure to have the Game window open and visible in the editor when you run the game. There's currently a bug in Unity 3.0 (and possibly in earlier versions as well) where the window resolution reported to the script does not match the actual resolution of the window inside the editor if the window isn't visible at the time the play button is pressed, leading to a viewport with the wrong size.

Comments

Hakimo said…
Hi, this code works like a charm but I seem to have hit a wall. For some GUI textures, I used a script that has mouse button function to make the guitexture a button. After using the camera ratio code, the collision area for the mouse button is off for some reason. Is there a way to fix it? Thanks.
- Hakimo
Lajos said…
Works perfectly, thanks a lot for this! ;-)
retn said…
Thanks for this great code snippet. Works perfectly.
Anonymous said…
Is that work for android devices...
Anonymous said…
Thanks man, really helpful. It works great. On android too.
Anonymous said…
Awesome! Thank you very much!
Unknown said…
Booyaka!!! This works like a charm!!! I am soooo grateful!!!
Unknown said…
I have a question related to this script. It works fine and sets the aspect ratio, but if you put a screenshot line to the very end of the script, it makes a whole screen screenshot from the camera (so in my case it will be a 16:9 aspect ratio picture) instead of taking only the camera's viewable area (which in my case is A4 size 297:210). Is there any solution to force the screenshot to A4 size too?
Joss said…
Good script and it's very easily to use it.

Really thank you.
Anonymous said…
Hi Adrian,
this is genius!! Helpt me a lot :D
Thanks for your work.
Amon said…
This is perfect for my needs. Pretty much the best resolution, aspect ratio helper code that I have found.

Cheers!
Danny said…
Very Nice Thanks a lot ! Works for Android devices
DarkMecha said…
Absolutely perfect for what I need, thanks so much!!!
Anonymous said…
Merci.
Anonymous said…
you are a hero
Unknown said…
u r great works awesome
Unknown said…
Perfect'm more problems in guitextures can help me?

Sorry my english.
Anonymous said…
Hey there.

An easier way that I'm using is to just always have a rectangular frame around my viewable area. The I gradually increase, decrease the rect while detecting the border with raycast. Once I get a hit on the border layer, I stop the rect scan. Takes literally a fraction of a second. This is fast too, just with a bit of faults. I mean, the real, REAL way to do it is to have individually coded resolutions lol

No one wants to do that, haha
GiantCatBallZ! said…
Thank God! Thank you very much!
Anonymous said…
godzilla hole on the black superman
Unknown said…
hi,
i will try above instruction, but its show nothing,
pls any one provide me any demo source asap.
thanks in advance.
Unknown said…
hi,
i will try above instruction, but its show nothing,
pls any one provide me any demo source asap.
thanks in advance.
Jason King said…
For people that are looking for additional aspect related support, I created a AssetStore extension that allows for easier aspect switching called AspectSwitcher(http://forum.unity3d.com/threads/released-aspectswitcher-easy-adjustments-to-ui-based-on-device-aspect.263004/). It provides a system for allowing you to easily specify different properties for different aspects. There are generally two method that most people use to switch aspects. One is to provide different game objects for each aspect. The other is to create custom code that modifies the properties of a single game object based on the current aspect. That generally requires a lot of custom coding. My extension attempts to alleviate a lot of that pain.
Ash Blue said…
This is the perfect script for cutscenes since users normally hate black bars during gameplay. Thank you so much. This just saved me a few days of work.
Unknown said…
Thanks for the great tutorial!! Its work lil charm
Anonymous said…
thanks man, this was exactly what i was searching for
Unknown said…
thanks for this! this just made my game playable to a wider audience.
Phyrexian said…
Thanks it works perfectly ^^
Anonymous said…
Thank you man! :D
Anonymous said…
You made my day man ... thank you so much !!!!!
Anonymous said…
Hello,

I did all things but nothing happn about black bar, can you help me pleas, the black bar is still here
virtual voyage:Excellent information on you.Thanks for sharing this valuable information with us. It’s really very informative and nice post.
Animation college in Indore http://www.virtualvoyage.edu.in/course/animation-and-film-making-college/
Anonymous said…
it helped but still the width on my S4 is stil not fit to screen.. PLS HELP :(
Unknown said…
Hi
Please,help for this question.
http://answers.unity3d.com/questions/1153253/how-can-i-fit-to-screen-my-gameobje.html
Anonymous said…
I just can say... Thanks!! Saved my day!! You rock!!
Unknown said…
Hi, this code works perfect!
Creaating perfect resolution for each screensize.

However, Im making a 2D game that allows the player to jump outside the camera and transport it to the other side of the screen.

I'm using this little code for it:


using UnityEngine;
using System.Collections;

void Start()
{
cam = Camera.main;
distanceZ = Mathf.Abs(cam.transform.position.z + transform.position.z);

leftConstraint = cam.ScreenToWorldPoint(new Vector3(0.0f, 0.0f, distanceZ)).x;
rightConstraint = cam.ScreenToWorldPoint(new Vector3(Screen.width, 0.0f, distanceZ)).x;
bottomConstraint = cam.ScreenToWorldPoint(new Vector3(0.0f, 0.0f, distanceZ)).y;
topConstraint = cam.ScreenToWorldPoint(new Vector3(0.0f, Screen.height, distanceZ)).y;
}

void FixedUpdate()
{
if (transform.position.x < leftConstraint - buffer)
{
transform.position = new Vector3(rightConstraint + buffer, transform.position.y, transform.position.z);
}
if (transform.position.x > rightConstraint + buffer)
{
transform.position = new Vector3(leftConstraint - buffer, transform.position.y, transform.position.z);
}
if (transform.position.y < bottomConstraint - buffer)
{
transform.position = new Vector3(transform.position.x, topConstraint + buffer, transform.position.z);
}
if (transform.position.y > topConstraint + buffer)
{
transform.position = new Vector3(transform.position.x, bottomConstraint - buffer, transform.position.z);
}
}
}


When in other resolutions this now fails from time to time, blocking my player from moving outside the camera or transporting it to soon / to late.

I'm not seeing it, tried some stuff but I never did this before.

Any help would be apreciated.
Unknown said…
Hi, it works well but now GUI not fit into the screen.
without this script UI works well but other things are not.
Please any help.
Unknown said…
If you add your main camera as render target for the GUI, you should have no problem.
Tally Services said…
Thanks for your article. I fount it very useful.
RobertoVMelo said…
It doens't work. The aspect ratio keeps the same no matter the resolution...
But when you choose resolutions like 800x600 or 1024x768, considering you chose an aspect ratio of 16:9 the game screen gets very small compared to the
screen of your computer. And that is not good for the users either.
Anonymous said…
Thank you very much for this useful snippet. Shame you don't upate this blog anymore...
Adriano said…
Thank you very much! This code worked fine and helped me a lot!
Anonymous said…
Thanks man.This is great working and simple code.
Oguzhan said…
You are absolute legend bro !!!
aldo said…
Ty so much for this AMAZING script! Works like a charm,
All you have to do just set width/height ratio
Unknown said…
Every time that I've come back to needing this script for something I'm stunned that Unity still doesn't natively support forcing a specific aspect ratio. Thanks for keeping this post around.
ayylmao said…
thanks, my nibba.
Just wanted to jump on here, In the Year of our Lord 2018, and say thank you for this piece of code.
Kate said…
Thank you so much from Korea :-)
Unknown said…
Good Job Bro!
Gabriel Samaan said…
Using the method: Auto Letter Box Asset (https://assetstore.unity.com/packages/tools/camera/auto-letterbox-56814)
you can change the camera by using the ViewPortRect, by changing her aspect you consequently fix the game aspect.
To fix the canvas aspects you have to go to Canvas Object > Canvas Scaler (Script) > Screen Match Mode > Expand, there you can organize the "Anchors" to place the camera in the best position (I recommend setting the background collor to black, wich will leave the edges of your game view black). Make sure to centralize the camera, not to expand out of the game view.

Text said…
I am pretty dissapointed about Unity did not still support it natively. It took me several days to figure out this..
I just had to chime in.. PERFECT!!! Thanks so much for this!
Fred Jefret said…
Even in 2019 I have reaped great benefit from this post. Thank you!
Anonymous said…
Works great! Thanks very much.
Anonymous said…
2019 Chiming in... Thanks !
Unknown said…
This is by far the biggest problem I've had with Unity and I'm stupidly emotional lol thank you so much man
Anonymous said…
Great script, thanks a lot!
CherryTree said…
Merci beaucoup d'avoir trouver et partager cette solution qui à résolu mon problème !
Je mes en favoris le site en cas d'autre question sur Unity
Merci encore !
Anonymous said…
This works perfectly for gameplay, but how would I keep the UI inside the game screen and not the black bars?
ColinStuart said…
I have been looking for this solution for so long, what I needed was the second camera to render the black!

Thank you so much.
Anonymous said…
Hello! I'm making a game with a 9:16 Aspect Ratio, but I don't know what to change to make it work. I tried a few things but nothing is happening.

Popular posts from this blog

Don't think "random", think "statistics"

Narrative and Consequences