Game Dev

Managing Screen Resolution and Aspect Ratio in Unity 3D

This article has been written using Unity 5.2.3 as a reference, many things could have been changed in the current version.

When it’s time to publish a standalone game made in Unity 3D, one of the things to do is ensuring that the game and its UI work fine on different display resolutions. Shipping your game with the Unity resolution dialog window turned on (Edit menu > Project settings > Player | Resolution and  Presentation : Display Resolution Dialog) is an easy way to let your users choose a windowed or fullscreen resolution for the game. But if you want to let them change the resolution from an in-game menu or if you have to enforce a specific aspect ratio, than you need to understand how Unity screen resolution management works, its connection to the PlayerPrefs and how to tune cameras to target a specific aspect ratio. I’ve come up with a basic screen resolution manager for Unity, tested on OS X and Windows. Here is the project on github: UnityScreenResolutionManager[a]. In this article I will explain in detail how it works.

Full Screen Resolution

resolution-and-presentation

Edit > Project settings > Player

Let’s see how the fullscreen resolution works in Unity. A set of parameters can be edited from Edit menu > Project settings > Player | Resolution and  Presentation (see image). The first thing to look is the fullscreen mode. You can choose between fullscreen window and exclusive mode on Windows. In exclusive mode your game will take control of the entire display. With this mode it is not possible to change the screen resolution at runtime, thus we have to avoid this mode and choose the fullscreen window mode instead. In fullscreen window mode, your game will run inside a maximized borderless window. This window will live in the current screen, thus inheriting the same resolution of the display where it has been created, no changes are made to the current display resolution when the application starts and when it is running. Now let’s see what this implies when you set a fullscreen resolution using the editor player settings:

  • When you check Default is native resolution in player settings, native means the current display resolution, not the actual native resolution of you computer monitor which can be larger than the current screen resolution.
  • When you select a Default Screen Width/Height in player settings greater than the current display resolution, Unity will use the current display resolution, even if it is smaller than your monitor native resolution (no display resolution changes are possible in fullscreen window mode). Let’s say that you have a full hd monitor and you set a 1280×720 resolution using the OS settings; when you launch a Unity application set with a default full hd resolution, the application will run inside a maximized window on your 1280×720 screen, no screen resolution change will occur.
  • When you select a Default Screen Width/Height smaller than the current display resolution, Unity will use this smaller size to render the current fram in memory and then upscale it to fit the full-resolution window. You will see larger pixels, as when you set a lower display resolution, but this upscale is done in engine, not by changing the actual display resolution.

As we have seen above, when dealing with screen resolutions in Unity, it is important to distinguish between the game viewport resolution and the underlying display resolution. Unity documentation talks about a general screen resolution which can be unclear if you don’t know much about the way Unity manages screen resolutions. In this article I will always specify if I’m talking about the display resolution or the game viewport resolution. You can control the screen resolution at runtime using the Unity engine Screen class:

  • Screen.fullscreen Toggles fullscreen/windowed mode.
  • Screen.width, Screen.height The current width/height of the game viewport in pixel.
  • Screen.resolutions aspect-ratiosAll fullscreen resolutions supported by the monitor. The resolutions included in this array are filtered by the Supported aspect ratios setting you can find in the player settings panel. If your monitor is set to a resolution smaller than native, Screen.resolutions will contain the native resolution but that resolution will not be actually available for your game; in fact, as seen above, it is impossible to increase the display resolution at runtime.
  • Screen.currentResolution This property has a different behaviour on Windows, OS X and Linux when you are in fullscreen mode.
    • On Windows it contains the current game viewport resolution (the one that you set with Screen.SetResolution), but in certain cases it can be different from (Screen.width, Screen.Height).
    • On OS X it contains the current display resolution (set by the OS).
    • When in windowed mode, Screen.currentResolution gives you the current display resolution both on Windows and OS X.
    • On Linux (tested on Ubuntu 14.10) this parameter is pretty useless on a multiple monitor configuration cause it will always return the resolution of the screen area covered by all the monitors both in fullscreen and in windowed mode.
  • Screen.SetResolution(int width, int height, bool fullscreen) Sets the game viewport width and height in pixels and switches between fullscreen and windowed mode. You are free to set a resolution not included in the array Screen.resolutions; you can choose any size smaller or equal to the current display resolution (not greater, see above). When you choose a resolution with an aspect ratio different from the current display aspect ratio, Windows can add letterbox or pillarbox black bands (only when you set the resolution in player settings, not at runtime), OSX will stretch the viewport on the entire display with no black bands thus changing the pixel aspect ratio and generating a distorted image. We’ll see below the best way to deal with aspect ratio in Unity.

Full Screen Aspect Ratio

As seen above, when you set a fullscreen resolution with an aspect ratio different from the current display aspect, Unity can insert black bands around the screen to keep the pixel aspect ratio. Unfortunately you cannot count on this behaviour for two reasons: it only works on Windows (OS X stretches the screen), and the black bands on Windows are not refreshing (Steam popups will leave a trail over these bands). The correct way to deal with aspect ratios and insert black letterbox/pillarbox bands is working with camera settings. There is a nice script on the Internet – AspectUtility.cs[b] – which is very simple to use: just add it to every camera in your scene. If you are using Unity legacy UI or NGUI, make sure to use screen space camera render mode and add the AspectUtility.cs to the UI camera. This script will set the camera rect to create some pillarbox/letterbox bands according to the proportion between the current and desired aspect ratio. It will also add a background camera to fill these black bands and guarantee screen refreshing for these areas. It also provides some utility methods to remap screen sizes and mouse positions, useful when you are working with the game UI. Using this script, the way you enforce screen aspect ratio in your game is:

  • Set a fullscreen resolution with the same aspect ratio of your display. In this way you are sure that Unity won’t stretch the screen thus preventing image distorsion.
  • Add the AspectUtility.cs script to each camera in your scene, using screen space camera rendering for UI.

I did some changes to the original AspectUtility.cs script in order to intercept screen resolution changes and update the camera rect accordingly.

PlayerPrefs

Every time you change the screen resolution, Unity saves the width, height and fullscreen/windowed mode in the application PlayerPrefs storage. Unity applications read these PlayerPrefs at startup and use these values to set the screen resolution for your game. This can lead to some strange behaviours when testing your applications:

  • When you make new builds of your application with different screen settings, the application will keep reading the old PlayerPrefs at startup ignoring the new player settings. You have to delete the current PlayerPrefs in order to test the behaviour of an application first run.
  • If you run your application on a display with a resolution smaller than the one specified in player settings, the screen will adapt to this smaller display and the new screen size will be stored in PlayerPrefs. Now, if you close the application and then you launch it again on a monitor with higher resolution (a common case is when you have a multi monitor setup with different screen sizes), your application will keep the previous smaller resolution even if now your monitor could support the native game resolution.

On Windows PlayerPrefs are stored in the registry under HKCU\Software\[company name]\[product name] key, where company and product names are the names set up in Project Settings. Just delete this registry entry to make sure that your application does not read old screen settings at startup. On Mac OS X PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. The same .plist file is used for both Projects run in the Editor and standalone players. Cleaning up PlayerPrefs on OS X is a bit harder than on Windows cause the application itself and the per user process “cfprefsd” both cache the preferences[c]. The easiest way I found to cleanup PlayerPres on OS X is to call PlayerPrefs.DeleteAll() inside an ad hoc cleanup scene in my Unity project.

Screen Resolution Manager

Now let’s see a bit of code of my screen resolution manager for Unity. Here is the project on github: UnityScreenResolutionManager. A basic screen resolution manager class should:

  • Compute a set of available fullscreen/windowed resolutions for your display (according to an optional desired aspect ratio) in order to let te users choose them in a menu.
  • Enforce a preferred aspect ratio at runtime.
  • Manage fullscreen to windowed transitions.

To compute the available resolutions, the manager needs to know the current display resolution. On Mac OS X it’s easy, just read the Screen.currentResolution property. When running in fullscreen mode on Windows, as seen above, this property gives you the current game viewport resolution, which can be different from that of the display. The solution I used to get the current display resolution when you start fullscreen is switching to windowed mode at startup, read the Screen.currentResolution property and then switch back to fullscreen. Here is the code:

The above code which is executed inside a coroutine, as you can guess if you notice the yield keywords. This because I need to wait one or two frames when changing resolution (the resolution is actually changed in the next frame after calling Screen.setResolution). After obtaining the current display resolution, it is possible to compute a set of resolutions, based on a list of predefined hardcoded widths.

I’m creating two lists, both for windowed and fullscreen resolutions. Here are the steps:

  • Add to the fullscreen list all the resolutions smaller than 80% of the current resolution.
  • Add to the fullscreen list half the value of the current screen resolution (only if greater than the smallest hardcoded resolution).
  • Add to the fullscreen list the current display resolution.
  • Add all resolutions smaller than 80% of the current resolution to the windowed list.

On Mac OS X (at least on Yosemite where I did the tests) there is a problem when you try to switch from fullscreen mode to windowed mode with a specific window size. The application, in fact, will pass from fullscreen to windowed with an animated transition of a couple of seconds. After this transition you have to call SetResolution again to ensure that the window is resized correctly. I wrote a piece of code for OS X which waits for this transition to end, here it is:

Here is a screenshot of the UnityScreenResolutionManager:

Resolution-manager-screenshot

A simple test scene and UI for the screen resolution manager.

Linux

The screen resolution manager has some problems on Linux, at least on an Ubuntu 14.10 where I did the tests. The aspect ratio enforcer works fine but the screen resolution module has some issues. As seen above, on a multi monitor setup it will get a wrong current display resolution and it will set a very large resolution corresponding to the area covered by all the screens. On a single monitor setup it works fine; the only issue is when you switch for the first time from fullscreen to windowed mode. You will get a maximized window which cannot be resized by script until you manually unmaximize it. Given these issues and the fact that on Linux it is impossible to test the infinite number of different configurations, I prefer to show the Unity screen resolution dialog  at startup on my Linux builds.

Notes

  1. UnityScreenResolutionManager project on github []
  2. AspectUtility.cs []
  3. Unity3d OS X Clean up player prefs / plist []

26 thoughts on “Managing Screen Resolution and Aspect Ratio in Unity 3D

  1. rhylvn dale

    hello sir. how do you use Screen.SetResolution(); on a multiple screen? cause it only set’s the main default one.

    Reply
    1. Giuseppe Post author

      Usually the game window is created in the main screen. So if the user doesn’t move it on another screen, I think there is no way to change resolution on a different screen. Bear in mind that SetResolution changes only the viewport resolution, not the actual screen resolution.

      Reply
  2. Kiriel Branson

    How do you download your code?

    The code on https://github.com/gportelli/UnityScreenResolutionManager….I was going to download it, then open it up in a Unity project and go through this with your notes above, testing how things work but I can’t see any way to download the files. Most of the files I can copy the content and put it into a notepad file but if there is a way to download the file that would be great.

    And by the way, this looks very informative. I am new and trying to figure out how to create my views and screens.

    Reply
      1. Giuseppe Post author

        Hi Kiriel, you can also just click on the green “Clone or download” button in the github project page and select “Download Zip”. No need to register or to use git at all.

        Reply
  3. Thuong

    Hello Giuseppe,
    Thank you for very useful stuffs. When I build and run .exe file, all of functions are ok but when I run directly on unity editor, it doesnt work as expected (when I click Fullscreen button, it does not switch to windowed mode). Would you explain about this point. Thanks!

    Reply
    1. Giuseppe Post author

      Hi Thuong,
      It is a feature of the unity editor: when you are running in editor you can’t toggle fullscreen nor changing resolutions. That’s why I included a screen logger class in the example project, because you can only test these stuff by running a build. Check out my screen logger plugin for an updated version of the logging class: http://www.aclockworkberry.com/unity-screen-logger/

      Reply
  4. D R Milton

    Hello, Thank you for your work!
    I have one issue: my game is in 16:9 ratio, but it only runs in correct proportions if the user’s screen is set to an aspect ratio of 16:10, where it has the horizontal black bars. If I change the screen aspect to a 16:9 ratio, the game is squashed vertically, with wider horizontal bars.
    Do you know a fix for this?
    I’m using Unity 5.0.0. In Player Settings I have Default Is Fullscreen checked, the Default Width 1280, Default Height 720, and Fullscreen Modes set to Fullscreen Window. My monitor is set to 1280×800.
    (I don’t know if this affects anything, but I’m still changing my canvases over to screen space camera to conform to your scripts. Some of them are still in screen space overlay…)

    Thank you for any help!

    Reply
    1. Giuseppe Portelli

      Did you take a look at the UnityScreenResolutionManager project? It is better to start from that codebase to build your resolution managing code.
      A couple of things that I’m doing in that project:
      – When the game starts, I set a screen resolution with the same aspect ratio of the actual display resolution. In this way I’m sure that Unity won’t stretch the screen thus preventing image distorsion.
      – I set the game desired aspect ratio in the ResolutionManager.TargetAspectRatio variable. (4/3 is the default value you can find in the code)

      Probably, the problem with your project is caused by the default screen resolution being set to 1280×720 in editor and never changed at runtime.

      Reply
  5. Matias

    Hi! Nice article!

    I’ve this problem.
    I’ve a second full hd monitor connected to my macbook 13”. This second monitor works as a non-mirrored screen, that means my macbook has a resolution of 1280×800 and my external screen 1920×1020.
    The problem is that Unity doesn’t care about it. I can’t change the resolution of the build more than the native resolution of the macbook, so when I open the project in the full hd screen, the build open in full screen mode but with a super ugly resolution.

    Any clue?

    Reply
    1. Giuseppe Post author

      If you want to obtain the resolution of all your displays, try using this array: Display.displays https://docs.unity3d.com/ScriptReference/Display-displays.html

      I can tell you my experience working with multi-extended-screens on Windows. When launching a fullscreen game or application, the display and resolution used by the application depends on the display defined as main screen in the OS. Try to set your external screen as the main screen using the OSX interface, then launch the build.

      Reply
  6. Jardel Antunes (Jarda)

    Is there a way to enforce some resolution on Unity games? I mean, already finished/compiled games. And I mean also resolutions supported by the game, not custom ones.
    I wouldn’t mind to mess around, as long as it turns out to be doable.

    Sorry for going a bit offtopic here, but I’m looking everywhere without any luck. I’m trying to avoid going through 50+ threads on Steam forums and asking every single Unity game developer: “Hey, I bought your game. Does it have any command line support?”

    Great article anyways.

    Thanks in advance..

    Reply
    1. Giuseppe Post author

      If the game is running on a fullscreen borderless window, you can set a display resolution on your OS and the game won’t change it but will probably set its fullscreen resolution to your current display resolution (minus letterbox bands if it is enforcing some aspect ratio).
      If the game is actually changing your display resolution, the result depends on the game implementation: if the game is saving user selected settings, it will run at the same resolution every time. One think you can do manually, is to edit its windows registry entries, as I explain in this article.

      Reply
      1. Jardel Antunes (Jarda)

        I’ve made some tests with 6 games, and after editing registry entries, almost nothing has changed.
        I’ve edited “Screenmanager Resolution Height_h[ten_digits_sequence]” (same for width) values, but it only works on games which show the graphics/input configuration window/launcher. I mean, the config window will show the new values, I just need to click “Play”, and this is better than nothing.
        Editing registry values does nothing if the game has no configuration window/launcher tho.
        Some games has ” ScreenWidht(or Height)_h[ten_digits_sequence]”, but it also did nothing after editing values.
        By the way, do you have any clue of what these “_h[ten_digits]” stands for? They are present in the majority of registry keys value names on Unity games.

        Command line and ini/cfg editing is the only thing I can think of, in order to force games to start on some resolution. Unity games in the other hand, provides none of these options. If I find a way to decrypt those “config.sav” I could be able to change the settings before the game starts, but I don’t think it would come in hand…

        Reply
      2. Jardel Antunes (Jarda)

        I had success with the following command line parameters:
        -screen-width “value”
        -screen-height “value”

        It seems to work on almost every Unity game I have. I need to open the exe properties, select Compatibility tab and tick the “Disable DPI Scalling” thing (not sure about the correct English string) for it to work as intended tho.

        Reply
  7. Spades

    Hey I’m trying out your solution, but when I enter fullscreen with alt-enter on windows, the resolution stays the same as in the windowed mode (even with black borders).
    Is there a way to get notified that the resolution should change to native?

    Reply
  8. Arantxa

    Hi!
    Thank you for this post! I have proven that on Windows it’s not necessary to switch to windowed mode just to set the Screen.SetResolution().

    I want to ask you if there is any way to banned screen rotation on windows EXE from script.

    Thank you in advance!

    Reply
  9. Giuseppe Post author

    Hi, this article is a bit outdated. It talks about Unity 5.2.3
    and many things could have been changed in the meanwhile.

    I don’t know if there’s a way to ban screen rotation, sorry.

    Reply
  10. bee

    HI Giuseppe….Did you know anything about Unity camera TargetDisplay…functionality???….i mean how to activate it(other that unity documentation,becuase it does’t work for me).

    Reply

Leave a Reply