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

Editor mode issues displaying Sprites from AssetBundle

Discussion in 'Editor & General Support' started by Buzzrick_Runaway, Sep 18, 2018.

  1. Buzzrick_Runaway

    Buzzrick_Runaway

    Joined:
    Jan 7, 2018
    Posts:
    15
    I'm struggling with an issue in Unity loading Sprites from a SpriteAtlas, downloaded in an AssetBundle.

    In our current game I am trying to implement AssetBundles to remove "Resources" folder usage, and reduce memory overhead (among other things).

    In the Game app, the downloaded sprites aren't rendering correctly when running in the editor, so I built a small test project to better understand the problem. Unfortunately the test project works perfectly, even though I'm using identical code to download and display the sprites. I'll refer to these two versions as TestApp and GameApp from here on. Just to reiterate, this issue is only a problem when running in the Editor (not the final device builds), however this is a game breaker for us because we simply can't develop and test the application. The turnaround getting builds to device is simply too long compared to running in the Editor.

    A simplified version of the script that I use for loading asset bundles is as follows. (This has been hugely simplified for brievity, including stripping out all object caching and error handling, etc)

    Code (CSharp):
    1. public IEnumerator GetSpriteFromBundle(string bundleURL, string spriteAtlasName, string spriteName, Action<Sprite> onLoadAction)
    2.     {
    3.         //  get the AssetBundle
    4.         AssetBundle bundle = null;
    5.         UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(bundleURL);
    6.         yield return request.SendWebRequest();
    7.         if (!request.isNetworkError && !request.isHttpError)
    8.         {
    9.             bundle = DownloadHandlerAssetBundle.GetContent(request);
    10.         }
    11.  
    12.         //  Get the SpriteAtlas
    13.         SpriteAtlas atlas = null;
    14.         if (bundle != null)
    15.         {
    16.             if (bundle.Contains(spriteAtlasName))
    17.             {
    18.                 AssetBundleRequest assetRequest = bundle.LoadAssetAsync<SpriteAtlas>(spriteAtlasName);
    19.                 yield return assetRequest;
    20.                 if (assetRequest.isDone)
    21.                 {
    22.                     atlas = assetRequest.asset as SpriteAtlas;
    23.                 }
    24.             }
    25.         }
    26.  
    27.         //  Get the Sprite
    28.         Sprite sprite = null;
    29.         if (atlas != null)
    30.         {
    31.             sprite = atlas.GetSprite(spriteName);
    32.         }
    33.         onLoadAction(sprite);
    34.     }
    The script that I use to call this to load the Sprite is as follows, (again error handling is stripped out):

    Code (CSharp):
    1. public void Start()
    2.     {
    3.         UnityEngine.UI.Image displayImage = GameObject.Find("Path/To/ImageObject").GetComponent<UnityEngine.UI.Image>();
    4.         StartCoroutine(
    5.              GetSpriteFromBundle(
    6.                 "https://mycdn.com/myassetbundles/gamesprites",      // AssetBundleURL
    7.                 "GameSprites",          //    SpriteAssetName
    8.                 "Icon1",                      //    SpriteName
    9.                 (sprite) =>
    10.                 {
    11.                     displayImage.sprite = sprite;
    12.                 })
    13.             );
    14.     }
    The end result of this is that everything works and loads correctly in the TestApp, but when playing the GameApp in the editor, the sprites are either invisible, or display as a weird image with 3 squares in it.

    The only difference that I can see is that when I use the frame debugger to look at the differences between the TestApp and the GameApp, the TestApp shows the SpriteAtlas texture in the batch, but the GameApp does not.

    As you can see here in the TestApp, the Texture is correctly set.
    SpriteAtlas_working.png

    And here in the GameApp, the texture is not set
    SpriteAtlas_broken.png

    Things that I have checked and confirmed between versions
    - Neither the GameApp nor the TestApp has any errors or exceptions.
    - It works correctly when built and deployed to a device (Only tested on Android so far)
    - A sprite object IS being returned in the onLoadAction callback in the GameApp.
    - I'm using the same AssetBundles and Sprites in both applications.
    - I've done side by side comparisons of the Image object settings in the inspector in both apps.
    - Both apps are set to the same build platform (I've tried Android, WebGL, and StandaloneWindows, and all have the same result)
    - The AssetBundles are built for the correct build platform (as above)

    The only difference that I can see between the TestApp and the GameApp is that the GameApp is much larger / more complex, and it has a scene change (we start with a loading scene before going to the in-game scene), but I don't see how either of those should affect anything.

    I've also set up and tested a version using AssetBundle.LoadFromFileAsync() and loading the file from the StreamingAssets folder, with the same results

    Is this a bug in the Unity Editor? What should I be looking at to try and fix this? We basically can't use AssetBundles until I find a solution.

    I've used the AssetBundleBrowser asset to set up the AssetBundles. (https://assetstore.unity.com/packages/tools/utilities/asset-bundle-browser-93571)

    I've tested with various versions of Unity, from older 2018.1 releases up to the latest release (2018.2.7f1 at the time of writing).

    (Cross posted on StackOverflow)
     
    Last edited: Sep 27, 2018
  2. Buzzrick_Runaway

    Buzzrick_Runaway

    Joined:
    Jan 7, 2018
    Posts:
    15
    I'm still digging into this with no progress.
    It's been suggested that we can't use SpriteAtlases in an AssetBundle (despite the fact that I have it working on my moble devices), so I should query for a Sprite directly. I've tested this and have the same result when testing in the Unity Editor.

    For completeness, here is the new code to query for a Sprite within an AssetBundle. Note that I'm also using LoadAssetWithSubAssetsAsync because it's been suggested that I need to get the containing SpriteAtlas (or something):

    Code (CSharp):
    1. private IEnumerator GetSpriteFromBundle(string bundleURL, string spriteName, Action<Sprite> onLoadAction)
    2. {
    3.     //  get the AssetBundle
    4.     AssetBundle bundle = null;
    5.     UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(bundleURL);
    6.     yield return request.SendWebRequest();
    7.     if (!request.isNetworkError && !request.isHttpError)
    8.     {
    9.         bundle = DownloadHandlerAssetBundle.GetContent(request);
    10.     }
    11.  
    12.     //  Get the Sprite
    13.     Sprite sprite = null;
    14.     if (bundle != null)
    15.     {
    16.         if (bundle.Contains(spriteName))
    17.         {
    18.             AssetBundleRequest assetRequest = bundle.LoadAssetWithSubAssetsAsync<Sprite>(spriteName);
    19.             yield return assetRequest;
    20.             if (assetRequest.isDone)
    21.             {
    22.                 for (int i = 0; i < assetRequest.allAssets.Length; i++)
    23.                 {
    24.                     sprite = assetRequest.allAssets[i] as Sprite;
    25.                     if (sprite != null && sprite.name == spriteName)
    26.                     {
    27.                         break;
    28.                     }
    29.                 }
    30.             }
    31.         }
    32.     }
    33.     onLoadAction(sprite);
    34. }
     
  3. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Buzzrick_Runaway likes this.
  4. Buzzrick_Runaway

    Buzzrick_Runaway

    Joined:
    Jan 7, 2018
    Posts:
    15
    Thanks for the suggestion VergilUa.
    I've tried switching to the legacy Sprite packer, but it still doesn't solve the problem. I have also attempted not using SpriteAtlases at all, and just pulling Sprites out of the AssetBundle and have had the same result.
    Ultimately I think that it is an issue with something in my project or scene that is causing the problem, not with the AssetBundle (because I can successfully load the Sprites in my TestApp), but I have no leads on where to even start looking
     
  5. Buzzrick_Runaway

    Buzzrick_Runaway

    Joined:
    Jan 7, 2018
    Posts:
    15
    Oh heck! You've actually helped point me in the right direction to solve it @VergilUa!

    It turns out if I set the SpritePacker mode (in Edit->Project Settings->Editor) to "Enabled for Builds" then the sprites aren't loaded properly, whereas if I set it to "Always Enabled" (the default I believe) then the sprites, and the SpriteAtlas is loaded correctly from the AssetBundle.

    Thanks!