Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to change the texture resolution at runtime and before loading the scene?

Discussion in 'Editor & General Support' started by AlanGameDev, Jul 6, 2014.

  1. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    Hello there.

    Note: read the last edit here.

    I would like to somehow change that 'Max Size' adjustment for the textures at runtime according to the screen resolution (up to 1024*1024, and manually configurable to 4096*4096).

    Of course it has to be something that 'tells' Unity to resize the textures before sending the data to VRAM because otherwise some low-end devices will surely crash due the lack of VRAM (sending a 4096*4096 texture to resize to 256*256).

    Another option would be to simply save the textures at various resolutions and load the correct one at runtime, I don't know if there's an easy way to do that though (they are spritesheets).

    Thank you in advance.

    PS: Please don't recommend me plugins because my budget is very low/nil and I did everything from zero, including virtual gamepad and gui.
     
    Last edited: Jul 6, 2014
  2. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    max size is editor only import setting so you need to use other way like save all various sizes to Resources folder and load the one you want to use during runtime

    there are a lot of articles and tutorials about this as its very common thing in mobile games, googling unity SD HD atlas loading might be a good start or just search the forum with keywords SD HD
     
  3. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    Thank you, but most of those threads end up with either plugins or with bad workarounds.

    I think a solution could be to set the default texture as the lower-res one, then if the screen can display beyond that, unload that low-res texture and load a higher resolution one and somehow replace the references to the low-res one for the higher-res one, however, I don't know:

    1-How to have a spritesheet in various resolution since you can't keep the mapping of the sprites among images with different resolutions
    2-How to 'replace' a texture for one with higher resolution.

    If there are threads/articles about that, please lemme know! I've googled the hell out of it and always ended up in NGUI/2DToolbox forums... I don't want plugins, I just need to know how to do those 2 things listed above.

    Any help is appreciated.
     
  4. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    First, are you targeting mobile? if so then don't load anything until needed using Resource class. What are you using for your 2D, Unity sprites or something of your own? remapping should be just simple math no matter what stuff you are using
     
  5. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    NOTE: Edited

    Yes, mobile and Unity sprites.

    Remapping is not simple because there's no easy way to remap pivot points (no way to get them), and also, I've optimized my textures for the Unity's 'Max Size' stuff, so I mapped all my sprites at 4096*4096 and fine-tuned them to make sure they look okay scaled down to 256*256px. I don't know the maths behind that to replicate.

    Perhaps a 'stupid' fix would be to duplicate the high-resolution spritesheets and set them different 'Max Size' settings... that is hardly a decent fix though, and I really doubt there's no better way to achieve such a simple functionality in Unity... Plus I think in this case every spritesheet will occupy the same amount of disk memory, equivalent to the high-res one.

    Also, I don't know how I can somehow switch the textures... you know, 'change' textureA for textureB so everything using textureA will now use textureB instead.

    Edit: After some testing, it seems duplicating the spritesheet and attributing different 'Max Size' to them doesn't occupy more disk space than necessary, so it's a valid approach imho. The problem now is just swapping the texture used by the sprites for the right one... I couldn't find a way to get the shared texture used by the sprites in order to replace them like a texture from any other material.
     
    Last edited: Jul 6, 2014
  6. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    Leave material textures empty to not load anything when scene is loaded and then assign the texture via code.

    This might help you for Unity sprites:

     
  7. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    But how do I 'assign' the texture in code? I need to somehow swap the Texture2d being used by the material that's being used by the SpriteRenderers (in this case the Default Sprite Material).
     
  8. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
  9. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    Yes, I've checked that and I can't simply replace all sprites individually because FindObjectsOfTypeAll either has a bug or is not intended for use during runtime because any changes on the objects will be saved on the prefabs (i have an older thread about that). Plus I think that's hardly a decent approach for the problem, I mean, looping all the things and stuff...

    Let's say I have one texture, texA, with two sprites mapped, and I have two GameObjects with SpriteRenderers in the scene that are using the sprites in texA, let's call them spriteRenderer1 and spriteRenderer2, these SpriteRenderers are using the same texture, texA, and the default sprite material, it's obvious that somehow the texA is being used by the sprite material, and that texA is shared across both sprites, that's why they batch together in a single draw call. So, let's say I have another texture, texB, how can I swap texA for texB? If you change the mainTexture of the material being used by spriteRenderer1, Unity will create a new material for it, so I need to somehow change the mainTexture of the material that is shared across both SpriteRenderers.
     
  10. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    You can replace them like that. If you looked the official Unity video and the examples code it's one of the suggested ways at the moment. One of the examples for sprites:

    Code (CSharp):
    1. public class ChangeQuality : MonoBehaviour {
    2.  
    3.     void Start () {
    4.         SetQuality ("HD");
    5.     }
    6.  
    7.     public static void SetQuality(string suffix)
    8.     {      
    9.         var renderers = FindObjectsOfType<SpriteRenderer>();
    10.  
    11.         foreach (var renderer in renderers)
    12.         {
    13.             // sprite name without suffix
    14.             var name = renderer.sprite.name.Split('@')[0];
    15.             var sprite = Resources.Load<Sprite>(name + "@" + suffix);
    16.  
    17.             if (sprite)
    18.                 renderer.sprite = sprite;
    19.         }
    20.  
    21.         Resources.UnloadUnusedAssets();
    22.     }
    23. }
    24.  
    For material switching there are different stuff to note about .maintexture .material .sharedmaterial. You can also check the 2D forum section which is mainly dedicated for Unity 2D.
     
  11. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    Thank you Ostwind, however, I would like to somehow change the texture being used on a 'global' basis and for an entire atlas, not for each SpriteRenderer on the scene and, specially, I don't want each SpriteRenderer to have an independent texture, here are my reasons:

    1- FindObjectsOfType, as opposite to FindObjectsOfTypeAll won't loop inactive objects, that's somewhat 'workaroundable' by getting all the unparented objects and looping their children (incl inactive), however, if the parent itself is inactive, you need to somehow have a reference for it. Nothing major though.

    2- There's no way, as far as I know, to prevent Unity from loading automatically a texture you don't want to be loaded. So, that approach is very hard to maintain, because whenever an object that uses other atlas is activated/become visible somehow (by enabling components, instantiating, etc.). Unity will load the unwanted atlas into VRAM possibly causing the game to crash in low-end devices. It's not easy to make sure no object is going to someway use a texture you don't want (at lease in my case), that can be considered a 'bug' but it's not easily 'debuggable' and may depend on various conditions.

    So, the only 'failsafe' way I can think is to somehow 'point' the textures to the others... To make things worse, I'm re-using sprites in other atlases in order to keep the 'game' layer in a single draw call (i'm targeting 7 draw calls at max). So, I have to keep track of all objects, including different pools, inactive scene objects, instantiables, 'animated' sprites (very simple, i'm using keyframed anims for most stuff), along with dynamically changing atlases... so I have to somehow keep track of all those things and variations and make sure that no one will have and unwanted atlas, which could possibly cause the game to crash... I'd say that the chance of something going wrong is extremely high due the 'volatile' nature of my game and the management of spritesheets(/atlases).

    I really would like to have a way to somehow just change the 'shared texture' used by the sprites in order to simplify that process immensely... so all objects that uses texA are 'redirected' to texB so the thing gets more reliable.

    If there's no way to do that, I'm going to write my own rendering solution since Unity has 'low-level' stuff afaik, no problem at all, I just want to make sure there's no easy way to do what I need since, imho, that's very very basic stuff.

    EDIT: In fact, if there's a way to 'lock' some resources so Unity won't load them it would be mostly okay for me because in this case the effect would be a texture glitch if I forget to change the texture of some object. That's somewhat acceptable imho.
     
    Last edited: Jul 7, 2014
  12. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    All textures referenced in any of the scene objects will get auto loaded to memory when scene is loaded so there must be no references to the textures you don't want Unity to load. Next to Asset bundles the Resources class and folder is the most common way to load stuff afterwards. There are workarounds to get for most cases you say but I suggest you ask a mod to move this thread (use report button) to 2D section as you might get more detailed help there sa Unity support is general area which all 2D don't follow. I have pro version myself and still using 2Dtoolkit etc. for my projects.

    Unity devs have said there (IIRC) that multires atlas handling (really) still needs improvement and getting improved in future after the new UI system has been rolled out.
     
  13. AlanGameDev

    AlanGameDev

    Joined:
    Jun 30, 2012
    Posts:
    437
    That's not true, let's say you have an object that is not visible at start that is using some texture you don't want loaded, so you 'unload' that texture using Resources.UnloadAsset, when the object becomes visible, Unity will load its texture.
    Yeah, I think 2Dtoolkit is still the way to go since the native 2D stuff is seriously lacking... I hope they introduce better ways to deal with sprite atlases soon...

    In any case, I managed to solve my problem because I discovered that no matter the size of the texture atlas, the mappings on it are preserved from the highest resolution or the resolution you've mapped the stuff (possibly, not tested). So, after some hundreds of lines of editor scripts and runtime scripts, I managed to make an extremely complex spritesheet manager for my game that is working a treat and uses 2kb of VRAM (small overhead).

    I'm not telling that Unity is bad or something, but for 2D it's hardly a good engine atm imho... I mean, it's surely 'possible' to make 2D game on it and the visual editor is fantastic, but it has some serious drawbacks. I think for PC it's not that problematic since you can pretty much squeeze something like 200 draw calls from any hardware nowadays, but for mobile, and specially Android (the hw goes from 'potato' to 'wtf_is_that'), it really doesn't have the tools necessary for a good optimization.

    Thank you Ostwind for your help.
     
  14. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,739
    hi
    this is an old thread, but i'm loading a texture at runtime, the issue is that I see a black or white screen while the Resource.Load is called and getting the texture. It last half a second but it's an annoying blink.
    I've tried on Awake, OnEnable and everywhere I could think of. Is there a way to load it before the object is visible so that you don't get that empty texture display before it's loaded?
     
  15. Anagr

    Anagr

    Joined:
    Oct 1, 2016
    Posts:
    22
    Just disable your gameobject in the Editor or in the Awake method, and keep it in this state until your texture loading. After that enable it again.