I recently had to start supporting Android devices in a product I'd built initial for iOS.
This was a scary proposition as there was a lot of GUI UI code that was pretty carefully laid out.
I'd partially implemented a solution before because I needed to support various versions of the iPad (which have various resolutions) and I wanted to design for the highest resolution (iPad Air) rather than stretch items from the lowest to the highest.
Anyhow, I found myself playing with GUI.matrix and solved my iOS needs in that fashion by modifying the Scale vector and leaving transform and rotation alone.
Now that I'm running on Android too, I found that I could simply extend my GUI matrix modifying code so that it was both resolution and aspect ratio independent.
I had to add two new things: Adjust the scale vector to account for scenarios when the actual aspect ratio was either greater or smaller than the 'target' aspect ratio. Add a translation component to the GUI.matrix so that the center of the screen was still the actual center of the screen.
I have been beating on it a bit this afternoon and so far it seems to solve the job for me (as long as I'm okay with non 4:3 aspect ratios have bars on the side - which I hide with camera color anyhow.)
It doesn't currently help with fullscreen textures (unless you can set the camera color to the base color of the texture) because you'll get vertical bars, but I'm not sure if that can be overcome and remain aspect ratio neutral...
Hopefully someone finds this useful.
//2D UI Scaling Related (treat all GUI code like it is running on iPad 4)
public const int m_nGUITargetResolutionWidth = 2048;
public const int m_nGUITargetResolutionHeight = 1536;
static private float m_nGUITranslationOffset = 0;
//Call some time before OnGUI in your classes that use OnGUI
public static void ScaleGUIMatrixToResolution()
{
float l_nScreenWidth = (float)Screen.width;
float l_nScreenHeight = (float)Screen.height;
float l_nAspectRatio = l_nScreenWidth / l_nScreenHeight;
float l_nTargetAspectRatio = (float)m_nGUITargetResolutionWidth / (float)m_nGUITargetResolutionHeight;
//Remember not to directly compare two floats
if( true == Mathf.Approximately( l_nAspectRatio, l_nTargetAspectRatio ) )
{
//Pretty much the same aspect ratio, so scale simply and leave translation alone
Vector3 l_oScale = new Vector3( ( l_nScreenWidth / (float)m_nGUITargetResolutionWidth ), ( l_nScreenHeight / (float)m_nGUITargetResolutionHeight ), 1.0f );
GUI.matrix = Matrix4x4.TRS( Vector3.zero, Quaternion.identity, l_oScale );
}
else
{
Vector3 l_oTranslate;
Vector3 l_oScale;
//Different aspect ratio, scale to fit the target region within the screen, compute translation to move the center of the GUI back to the actual screen center
if( l_nAspectRatio > l_nTargetAspectRatio )
{
l_oScale = new Vector3( ( l_nScreenWidth / (float)m_nGUITargetResolutionWidth ) * ( l_nTargetAspectRatio / l_nAspectRatio ), ( l_nScreenHeight / (float)m_nGUITargetResolutionHeight ), 1.0f );
m_nGUITranslationOffset = l_nScreenWidth - ( l_nScreenWidth * ( l_nTargetAspectRatio / l_nAspectRatio ) );
l_oTranslate = new Vector3( m_nGUITranslationOffset / 2.0f, 0.0f, 0.0f );
}
else
{
l_oScale = new Vector3( ( l_nScreenWidth / (float)m_nGUITargetResolutionWidth ), ( l_nScreenHeight / (float)m_nGUITargetResolutionHeight ) * ( l_nAspectRatio / l_nTargetAspectRatio ), 1.0f );
m_nGUITranslationOffset = l_nScreenHeight - ( l_nScreenHeight * ( l_nAspectRatio / l_nTargetAspectRatio ) );
l_oTranslate = new Vector3( 0.0f, m_nGUITranslationOffset / 2.0f, 0.0f );
}
GUI.matrix = Matrix4x4.TRS( l_oTranslate, Quaternion.identity, l_oScale );
}
}
↧