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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How can I load textures in the background?

Discussion in 'Scripting' started by andcuriouser, Aug 26, 2013.

  1. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    I've written a book-type app that displays several 2k textures on each page. Obviously, I ran into memory issues when I tried to make a mobile version of the app, so I redid things so that textures are only loaded for the current page, the previous page, and the next page (automatically unloading any textures outside that). The problem is, there's a horrible pause--almost half a second--when new textures are loaded in, which happens every time the user changes the page.

    Is there any way to have this texture loading happen in the background?

    Right now I'm just loading them from the Resources folder like this:

    Code (csharp):
    1. child.renderer.material.mainTexture = Resources.Load(page + "/" + child.name);
     
  2. karljj1

    karljj1

    Joined:
    Feb 17, 2011
    Posts:
    440
  3. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    I'd tried that once before, but for some reason I couldn't get it working smoothly, almost certainly because I don't quite understand how to properly use coroutines. This is my code right now:

    Code (csharp):
    1. function LoadTexture(textureName:String, destination:Transform) {
    2.     var www:WWW;
    3.     www = new WWW("file://"+Application.dataPath + "/Resources/"+textureName+".png");
    4.     yield www;
    5.     destination.renderer.material.mainTexture = www.texture;
    6. }
    7.  
    8. function ProcessActivatePage(pageGO:GameObject) {
    9.     var page = pageGO.name.Substring(5, 2);
    10.     Debug.Log("Activating " + page);
    11.     for(var i = 0; i < pageGO.transform.childCount; i++) {
    12.         var child = pageGO.transform.GetChild(i);
    13.         if(child.name.Substring(0, 2) == page) {
    14.             StartCoroutine(GameObject.Find("_master").GetComponent(pageControl).LoadTexture((page + "/" + child.name), child));
    15.         }
    16.     }
    17. }
    This is totally working--the textures are loading as expected. But things freeze every time I load in a texture (according to the profiler, the three coroutines that launch (to load the three new textures) are taking 490ms to execute, which is freezing the engine...which is the exact opposite of what a coroutine should do, isn't it?). How do I make the texture load happen in the background and not cause everything to freeze up?
     
    Last edited: Aug 26, 2013
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Coroutines aren't threads; also, using file:// is an atomic operation, whereas http:// can take place over a number of frames. I doubt that's the issue though; creating a 2Kx2K texture is probably where most of the time is coming from, and there's not really anything you can do about that, although turning off mipmaps would help (those aren't something you'd really need for page graphics).

    --Eric
     
  5. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    Does that mean there's really no benefit to using a WWW class instead of Resources.Load to get the texture?

    Right now the textures being loaded in are PNGs. Would putting these into an Asset Bundle help? Obviously there are games that manage to pull in large textures without freezing the engine.

    The Texture Type is set to GUI for each of the images, so they're already being loaded without mipmaps.
     
  6. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    I found this elsewhere:

    So, does that mean that Resources.Load was already as fast as I'd be able to load something? And there's no way to load these textures without having the program hang for half a second?

    There has to be a better solution. How do games that load in huge textures during gameplay do it without pausing?
     
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Resources.Load can't load external images...also...

    You can't use PNGs in Unity directly (including Resources.Load), since no graphics card supports them; you can only use hardware compression, or no compression. The only way to use PNGs is to store them as external files and load them either using System.IO classes or the WWW class.

    Not if you're loading external images; in that case you have to specify the format yourself.

    --Eric
     
  8. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    Right. That's the purpose of the Resource folder, right? It should contain the textures already converted to a native format. So, when I load a texture like so...

    Code (csharp):
    1. child.renderer.material.mainTexture = Resources.Load("whatever_texture");
    ...that texture doesn't need to be converted from PNG--it's already good to go. So I'm doing things right.

    So what causes the half-second pause? If they're in the Resources folder, they don't need to be converted to a different format, so that's not the problem. Is applying a 2k texture to a plane really so heavy an operation that I should expect the engine to completely hang for a few hundred milliseconds while it happens? And if so, how do other games handle this? There are a lot of examples of dynamic LOD that brings in high-resolution textures during gameplay. How do they manage to do it without hanging?
     
  9. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    Is anyone able to help me out with this? This is really the one major hiccup I've run into with Unity. There has to be a way to apply a 2k texture to a plane without having the entire engine freeze for a few hundred milliseconds--dynamic LOD systems do it all the time. Can anyone point me in the right direction?
     
  10. andcuriouser

    andcuriouser

    Joined:
    Jul 17, 2013
    Posts:
    10
    I FIGURED IT OUT.

    Oh good lord. Of course, the answer lies in the thing I didn't mention. It appeared that the hiccup was happening when I was pulling in the texture. It wasn't. It was happening when I was sloppily unloading the previous textures in the same function, which I just assumed was going to be a light action. Apparently I had written it in the worst way possible. I rewrote that part of the function, and now things are much, much smoother.

    Sorry I led people so far down the wrong path. But I learnt a lot about dynamically loading textures in the process, which will definitely help me in the future. Thanks :)
     
  11. jcamelo

    jcamelo

    Joined:
    Mar 4, 2014
    Posts:
    1
    Hi. So I have the same problem you had and I would just love some help.

    I'm trying to load a texture into a cube. Used WWW to download and apply the texture. It's a JPEG with usually 2400x2400 (I'm want to use this for different textures). For testing I put the cube spining and apply the texture, to see if it freezes or not, and it does for about 1 second, maybe less. It's not much but I still don't want it to freeze, that's my goal, my project, to remove the freezing, make it still interactive with the user.

    I had various ideias like using JPEG decoding libraries and trying to put them on threads or a bunch of coroutines but so far that hasn't helped either.
     
  12. U3dGeek

    U3dGeek

    Joined:
    Mar 9, 2017
    Posts:
    2
    I also have the same problem now.
    I am developing mobile camera app and I want to load the saved images from the local storage of the mobile phone.
    Everything is okay and I load the images using system.IO.
    The only issue is loading time is too long, how can I handle it as async or can I use thread for loading textures?
    The app get freeze when I load the images from the local storage and it is really a critical problem.
     
  13. MS80

    MS80

    Joined:
    Mar 7, 2014
    Posts:
    346
    Did anyone found a solution for this?

    How can it be that Unity can't load textures in the background (www and file://) without freezing?!?

    On my workstation (win10, GTX1070, 16GB RAM, i5 3,4GHz, SSD, Unity 5.6.0f3) I can load textures (via www and file://) with 512x512pixels without freezing. But as soon as the resolution gets higher (1024, 2048, 4096) loading without freezing is not possible. Bigger textures cause longer lags, of course.

    Any help or hint is welcome. Are there other ways of loading textures in the background (from external dir)?
     
    Last edited: May 5, 2017
  14. dpgdemos

    dpgdemos

    Joined:
    Apr 28, 2014
    Posts:
    24
    I'm having a lag issue as well, but my issue occurs when setting the main texture. By the way, the WWW class does not block the thread. The lag occurs when setting the texture.

    Code (CSharp):
    1. var www = new WWW("file://" + path);
    2. while (!www.isDone)
    3.     yield return null;
    4.  
    5. // Lag occurs here.
    6. r.material.mainTexture = www.texture;
     
  15. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,642
    Use UnityWebRequest.GetTexture(), that will create Texture in background.
     
    andrew-lukasik likes this.