Author Topic: Feature Request: Scaling GUI using "Real World" units.  (Read 6174 times)

davidgutierrezpalma

  • Guest
Feature Request: Scaling GUI using "Real World" units.
« on: June 23, 2013, 06:22:47 AM »
At this moment, we can use two different scaling options at the UIRoot:
  • Pixel Perfect: each GUI element will always have the same size in pixels regardless of the screen resolution and dpi.
  • Fixed Size: each GUI element will be scaled so it uses the same percentage of the Screen.height regardless of the screen resolution and dpi.

Let's suppose we have a lot of text that has been optimized for a normal medium-res screen:
  • If we try to read that text on a small high-res screen, it doesn't matter if we choose the Pixel Perfect or the Fixed Size option because the text would be so small that we couldn't read it comfortably on that screen.
  • On the other hand, if we try to read the same text on a large low-res screen, the text would be so large (in real world units) that we would waste a lot of screen space that could be used for displaying other GUI elements (for example: more text).
For that reason, I think it could be useful to have a Fixed Real World Size option for the UIRoot component that would make the text retain the same size (in "Real World" units) in every screen, regardless of their size and resolution. We could implement such feature if we take into account the Screen.dpi (in addition to the Screen.height) when we calculate the scale of the different elements of the GUI:

  1. public float dpi{
  2.         get{
  3.                 float dpi = Screen.dpi;
  4.                        
  5.                 // If Unity is unable to detect the DPI of the screen,
  6.                 // 1) Use 160 DPI as default value for mobile devices
  7.                 // 2) Use 72 DPI as default value for other Mac.
  8.                 // 3) Use 96 DPI as default value for other platforms.
  9.                 if (dpi < Mathf.Epsilon){
  10.                         if      (
  11.                                         Application.platform == RuntimePlatform.Android ||
  12.                                         Application.platform == RuntimePlatform.IPhonePlayer
  13.                                 ){
  14.                                 return 160f;
  15.                         }else if(
  16.                                         Application.platform == RuntimePlatform.OSXEditor ||
  17.                                         Application.platform == RuntimePlatform.OSXPlayer ||
  18.                                         Application.platform == RuntimePlatform.OSXWebPlayer ||
  19.                                         Application.platform == RuntimePlatform.OSXDashboardPlayer
  20.                                 ){
  21.                                 return 72f;
  22.                         }else{
  23.                                 return 96f;
  24.                         }
  25.                 }
  26.                 return dpi;
  27.         }
  28. }
  29.  
  30. public float GetRealWorldSize(int pixels){
  31.         // The dpi of the devices are usually measured in diagonal,
  32.         // so we need to calculate the "diagonal number of pixels"
  33.         // per inch to calculate the correct pixel size (in inches).
  34.         float pixelSize = Mathf.Sqrt(2f) / this.dpi;
  35.        
  36.         return (float)(pixels) * this.pixelSize;
  37. }
  38.  

We could use the code above to calculate the "Real World" size of a GUI element and we could use that information to modify the scale such element so its "Real World" size is the same in every screen. If we had the text from my previous example, it would fill a large portion of the screen on the small high-res screen and it would fill a small percentage of the screen on the large low-res screen, but the text would be readable on both screens because the "Real World" size of the text would be exactly the same on both cases.

I think I could implement this feature without many problems, but it would be a pain in the ass to re-apply my changes with every new release (and we know that NGUI is updated very often ;D). That is the reason why I'm making a feature request instead of implementing this feature myself... ;)

//----------//

Edited for including a different "default dpi" for Windows and Mac platforms.
« Last Edit: June 23, 2013, 05:23:10 PM by davidgutierrezpalma »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #1 on: June 23, 2013, 10:20:55 AM »
And how would this DPI be used? Not sure what the '72' or '162' is going to be used for afterwards.

davidgutierrezpalma

  • Guest
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #2 on: June 23, 2013, 05:18:16 PM »
According to the Unity documentation, Screen.dpi will return 0 if Unity is unable to determine the dpi of the screen, so I was trying to provide a reasonable "default value" for each platform in case Unity couldn't retrieve the dpi of the screen. Why have I chosen those "magic numbers"?

I have chosen 160 dpi as the default value for mobile platforms because, according to the Android SDK documentation, "a 160 dpi screen is the baseline density assumed by the system for a 'medium' density screen", so I thought it was a good idea to use that value.

I chose 72 dpi as the default value for non-mobile platforms because I read in the Wikipedia that 72 dpi has been the default dpi value for Mac OS since 1980, but I didn't realize that the default dpi value for Windows is 96 dpi, so the code above should be modified to provide a different "default dpi values" Windows and Mac...
http://blogs.msdn.com/b/fontblog/archive/2005/11/08/490490.aspx

About Linux, it seems that different distros use different "default dpi values", but I have seen a few distros that uses 96 dpi as default, so I think we can use that value safely.

//----------------------------------------//

I think the best place to invoke the GetRealWorldSize() method would be on the UIRoot script, something like this:

  1. public int activeHeight
  2. {
  3.         get
  4.         {
  5.                 int height = Mathf.Max(2, Screen.height);
  6.                 if (scalingStyle == Scaling.FixedSize) return manualHeight;
  7.                
  8.                 //---------------------------------------------------------------
  9.                 // MY CHANGE (start)
  10.                 //---------------------------------------------------------------
  11.                 if (scalingStyle == Scaling.FixedRealWorldSize) return GetRealWorldSize(manualHeight);
  12.                 //---------------------------------------------------------------
  13.                 // MY CHANGE (end)
  14.                 //---------------------------------------------------------------
  15.  
  16. #if UNITY_IPHONE || UNITY_ANDROID
  17.                 if (scalingStyle == Scaling.FixedSizeOnMobiles)
  18.                         return manualHeight;
  19. #endif
  20.                 if (height < minimumHeight) return minimumHeight;
  21.                 if (height > maximumHeight) return maximumHeight;
  22.                 return height;
  23.         }
  24. }
  25.  

Maybe it would be interesting having a "Scaling.FixedRealWorldSizeOnMobile" value too...
« Last Edit: June 23, 2013, 05:28:53 PM by davidgutierrezpalma »

DragonSpawn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #3 on: March 02, 2014, 01:58:59 PM »
I can't really stress how much this is missed.
David mentions mostly text, but the same applies to textures.
The current options available in NGUI doesn't quite suit GUI development on mobiles.
Pixel perfect doesn't fit all sizes, and Fixed uses scaling which isn't really what you want to use when spanning a wide range of resolutions.
https://developer.android.com/guide/practices/screens_support.html
Using density-independent pixels should be a third alternative.
That way you are guaranteed to always have the GUI look the same on devices on all shapes and resolutions.
I had this for the GUI I was working on, but it was taking too much of my time away from gameplay coding so I wanted to check out some other plugins, but it doesn't really seem that anyone has given it much thought.

Having this, and with the user creating atlases for different densities, you would have pixel perfect guis on all mobile devices, without need for scaling.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #4 on: March 03, 2014, 12:29:58 AM »
To add support for a DPI-based UIRoot, all you need to do is use a script like this:
  1. using UnityEngine;
  2.  
  3. public class SetHeightBasedOnDPI : MonoBehaviour
  4. {
  5.     void Start()
  6.     {
  7.         UIRoot root = GetComponent<UIRoot>();
  8.         float dpi = Screen.dpi;
  9.         if (dpi == 0f)
  10.         {
  11.             if (platform == RuntimePlatform.Android ||
  12.                 platform == RuntimePlatform.IPhonePlayer ||
  13.                 platform == RuntimePlatform.BB10Player ||
  14.                 platform == RuntimePlatform.WP8Player) dpi = 160f;
  15.             else dpi = 96f;
  16.         }
  17.         root.manualHeight = Mathf.RoundToInt(Screen.height * 96f / dpi);
  18.     }
  19. }

DragonSpawn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #5 on: March 03, 2014, 02:37:56 PM »
Thanks.
Following that example I got it working mostly. The problem with that piece of code is that it resizes based on whether it is landscape or portrait mode.
I however modified it with the example here http://www.tasharen.com/forum/index.php?topic=2397.0 and got it working perfectly.

Should definitely be it's own scaling style in my opinion.

Thanks for the help.

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #6 on: March 03, 2014, 04:08:49 PM »
Personally, I'd like to be able to set some sort of dpi for touch input as well, so it's not stuck on a certain pixel amount for drag and click distinctions. For right now, I tend to use an external script that calculates the dpi (either based on screen.dpi or custom stuff) and sets the pixel values at run time.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Feature Request: Scaling GUI using "Real World" units.
« Reply #7 on: March 03, 2014, 10:42:16 PM »
You can currently set both the DPI adjustment and the "shrink UI in portrait mode" setting on the UIRoot in the Pro version.