Scale A Quad or Sprite to fit screen ?

Hi,

I’m setting up my title screen for my small game, and I’d like to ask for some help with that.

I have a title graphic, which is a GUITexture, and beneath that I have a 3D object which will later become my ‘play’ game button once I add the scripting.

I originally set up a backdrop behind all of this as a GUITexture with an x and y scale of 1 to fit the camera resolution perfectly, but then I lost my 3D object because the GUITextures are always rendered on top.

So, I created a sprite, and attempted the following code to scale accordingly, which kind of works in landscape mode only, but it doesn’t fit the screen fully, I have a large gap at the top, and it also doesn’t work in portrait resolutions : -

using UnityEngine;
using System.Collections;

public class ScaleSprite : MonoBehaviour {

    // Use this for initialization
    void Start () {

        SpriteRenderer sr = GetComponent<SpriteRenderer>();

        float worldScreenHeight = Camera.main.orthographicSize * 2;
        float worldScreenWidth = worldScreenHeight / Screen.height * Screen.width;

        transform.localScale = new Vector3(worldScreenWidth / sr.sprite.bounds.size.x, worldScreenHeight / sr.sprite.bounds.size.y, 1);

    }
  
    // Update is called once per frame
    void Update () {
  
    }
}

Anybody offer any advice as to why, or offer a better solution, one that would work in both portrait and landscape would be great, simple scale whatever sprite I assign it to, to ‘whatever’ resolution is chosen ?

Thanks

Bump… Anybody can help, would really like to get this working correctly ?

Thanks

Fixed part of my problem, I’d not set the camera to sit at exactly 0 on the x and y axis, now I don’t get the gap ! :slight_smile:

Currently my script works in the following resolutions ( I’m working with Android platform ) : -

16:10 Landscape - WORKS

3:2 Landscape - WORKS, but… doesn’t seem to visually scale any differently from 16:10, i.e. when switching from 16:10 to 3:2, image stays same size, suggesting stretching beyond the width of the screen instead of the screen width only

WXGA Landscape ( 1280x800 ) - WORKS

WSVGA Landscape ( 1024x600 ) - Gaps either side

FWVGA Landscape ( 854x480 ) - Gaps either side

WVGA Landscape ( 800x480 ) - Gaps either side

HVGA Landscape ( 480x320 ) - WORKS

Seems like I’m fairly close to getting what I require, I’ve also figured out what I need to change in my calculation should I target a Portrait orientation, but all I’m interested in at this stage is the Landscape mode.

So… Anyone can help with some code suggestions for the 3 landscape modes that have gaps still, or 4 if you include the 3:2 Landscape problem listed above ?

Thanks

4.6 GUI uses anchor points to solve this problem really well. Look into it. It’s really cool.

I hope I didn’t misunderstand the question. I’m not sure if you’re always trying to fill the screen but I’m assuming you are.

using UnityEngine;
using System.Collections;

public class ScaleToFillScreen : MonoBehaviour
{
    private SpriteRenderer sr;
    private Transform _transform;
    public int pixelsToUnityUnits = 100;
    public Camera cam;
    public bool followCamera = true;

    // Use this for initialization
    void Start()
    {
        _transform = transform;
        sr = GetComponent<SpriteRenderer>();
        cam = (cam != null) ? cam : Camera.main;
    }

    // Update is called once per frame
    void Update()
    {

        Sprite sprite = sr.sprite;
        float aspectRatio = Screen.width / (float)Screen.height; // in respect to width

        // Guesstimation
        int orthoPixelsY = Mathf.CeilToInt(cam.orthographicSize * 2  * pixelsToUnityUnits);
        int orthoPixelsX = Mathf.CeilToInt(orthoPixelsY * aspectRatio);

        // orthoX and orthoY are obviously not the same as the screen resolution, but we can take advantage of the fact that they're scaled based
        // on unity units and ignore calculating based on screen pixels

        // find the ratio in scales along each respective axis' and assign as the new local scale
        Vector3 newScale = new Vector3(orthoPixelsX / (float)sprite.rect.width, orthoPixelsY / (float)sprite.rect.height, 1f);
        _transform.localScale = newScale;

        if(followCamera)
        {
            Vector3 camPosition = cam.transform.position;
            Vector3 newPosition = new Vector3(camPosition.x, camPosition.y, _transform.position.z);
            _transform.position = newPosition;
        }
    }
}

Sorry if I was off the mark. I’m not sure if you want to always fill the screen as the Aspect Ratio will be ignored and stretch your image oddly.

Edit: Actually ignore the follow Camera bit. That was strictly something I thought of for 2D play. It wont work on a 3D camera that is moving around a lot.

Edit2: Renamed the script to ‘ScaleToFillScreen’ since that better explains the functionality of the script.

2 Likes

Hi, Stoven

Thank you for reply, it is highly appreciated and I promise it will be studied intently.

The background image I have is a mixture of gradients, so stretching it out in any fashion will not be noticeable, the main logo for my game is a GUITexture, which I scale to fit the aspect ratio seperately in a different script. I have a 3D GameObject that is placed underneath my logo that will be my ‘PLAY’ button, but obviously this was previously hidden behind my original ‘background’ guitexture, by using a sprite, and your help with the script, my title screen will work correctly now and the ‘play’ button will be shown now ! :slight_smile:

The camera addition is actually very useful, I will comment it out for now, but I’m sure I will use this again in future !

Thanks again for all your efforts, I owe you a beer. :wink:

Regards

I didn’t realize what Orthosize actually meant until after reading into things, questioning it and looking at the unity units on the grid. It makes a lot of sense, but because of my uncertainty that unity units are always 1 unit per 100 pixels I added the pixelsToUnityUnitys value so it can be adjusted if there’s any possible chance one can adjust pixels per unity units.

Makes sense, and it works very nicely.

Misterselmo : Apologies, missed your post there, I’ve not moved to 4.6 as yet, as I’ve just been sticking with the public releases, the 4.6 GUI stuff looks nice and a lot easier to work with than the current integration, looking forward to the 4.6 public release ! :slight_smile:

Regards.

Sorry, but it’s wrong. GUITexture and GUIText components using depth camera, like other 3D objects.

OnGUI system no. Use a depth variable only affects the GUI elements draw in OnGUI function. And these, yes, are always rendered on top scene 3D objects.

You need other camera to using other renderer depth. Project example with two cameras and GUITexture: 7zip Download - Free 7-zip for Windows 11 - Get 7-Zip

That apply Extents layer to GUITexture and some 3D objects(terrain).

First Camera renders objects with Extents Layer and Skybox, and second camera renders the rest.

Hi, IsGreen

Thanks for your clarification, I actually looked at this technique also when researching this, but it didn’t work for me when I initially tried it, your scene example is helpful.

Regards

EDIT, I’m curious, with both techniques, what would people recommend as best method on Android platform ?