Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Addressables and Sprite Atlas

Discussion in 'Addressables' started by HugoClip, Nov 16, 2020.

  1. HugoClip

    HugoClip

    Joined:
    Feb 28, 2018
    Posts:
    52
    Hello fellow developers,

    I require help figuring out what happens when you tick the box in the atlas window -
    Include In Build and mark the atlas itself as an Addressable.

    Does it get duplicated in the built in assets and the asset bundles?
    How do direct references in prefabs to sprites in the atlas interact with the atlas? Do they actually use the atlas or do they ignore it and the sprite itself gets dragged into the asset bundles?
    What's even the best practise here?

    There are so many possibilities, it's kinda of confusing. If anyone knows how this system works I would be grateful if you could help me.
     
  2. CharBodman

    CharBodman

    Joined:
    Sep 20, 2018
    Posts:
    36
    What was the result of this? I'm curious as well.
     
  3. Shawn-Halwes

    Shawn-Halwes

    Joined:
    Jul 17, 2013
    Posts:
    51
    Is this explained anywhere? I am also curious what occurs with the sprite references, sprite textures that are in an addressable group and sprites being packed? Where do all the resulting packed sprites atlas textures go? How does that affect asset bundles?
     
  4. LilMako17

    LilMako17

    Joined:
    Apr 10, 2019
    Posts:
    43
    from my own experimenting:
    1) "include in build" ENABLED + marked addressable in remote bundle = atlas textures are duplicated, one copy will be packed with the build and one will be packed in the bundles.
    Any client embedded assets that reference sprites will reference the built-in one, and stuff via addressables will reference the remote one. functionally it works fine, but from a memory management perspective, this is bad and should be avoided.

    2) "include in build" DISABLED + marked addressable in remote bundle = one copy in a remote bundle.
    Any references to sprites in the atlas that are embedded in the client resources (ex: UI prefabs with Image components that reference sprites) will show up as white squares, but will trigger SpriteAtlasRequested flow* (https://docs.unity3d.com/ScriptReference/U2D.SpriteAtlasManager-atlasRequested.html), which you can setup to do late-binding in code, which will auto-magically re-assign all the sprites and make everything work. (you will have to go through this flow every time you unload / reload the atlas). You'll need to load the sprite atlas asset explicitly via addressables for this, not the sprites.

    I have not tested anything with sprite atlas variants.

    *note on SpriteAtlasRequest flow: these calls don't trigger in the editor in "Use Asset Database" mode.

    sample code:

    Code (CSharp):
    1. public class AssetManager
    2. {
    3.     private Dictionary<SpritePreloadTag, List<SpriteAtlas>> _loadedSpriteSheets = new Dictionary<SpritePreloadTag, List<SpriteAtlas>>();
    4.     private Dictionary<string, SpriteAtlas> _guidToSpriteSheet = new Dictionary<string, SpriteAtlas>();
    5. private Dictionary<string, Action<SpriteAtlas>> _lateBindingCallbacks = new Dictionary<string, Action<SpriteAtlas>>();
    6.  
    7.      public AssetManager()
    8.     {
    9.         SpriteAtlasManager.atlasRegistered += (spriteAtlas =>
    10.         {
    11.             // this gets called anytime a sprite sheet is loaded explictly
    12.             //UnityEngine.Debug.Log("spriteAtlas  loaded ???: " + spriteAtlas.name);
    13.         });
    14.         SpriteAtlasManager.atlasRequested += ((name, bindAction) =>
    15.         {
    16.             UnityEngine.Debug.Log("spriteAtlas  requested: " + name);
    17.             _lateBindingCallbacks[name] = bindAction;
    18.         });
    19.     }
    20.  
    21.     public async Task PreloadSprites(SpritePreloadTag tag)
    22.     {
    23.         Log.Debug("Start loading sprites tag: " + tag);
    24.         var preloadSet = new HashSet<AssetReference>();
    25.  
    26.         var spriteSheetGuids = new HashSet<string>();
    27.         foreach (var guid in PreloadableUtility.GetSpriteSheets(tag))
    28.         {
    29.             spriteSheetGuids.Add(guid);
    30.         }
    31.  
    32.         // this is here for sprites that are serialized in client packed prefabs.
    33.         // unity will strip them out at build time, and these callbacks will load them back
    34.         // into the UI prefabs
    35.         // we also keep track of these so we can explicetly unload them
    36.         foreach (var guid in spriteSheetGuids)
    37.         {
    38.             if (_guidToSpriteSheet.ContainsKey(guid))
    39.             {
    40.                 Log.Debug(_guidToSpriteSheet[guid].name + " already loaded");
    41.                 continue;
    42.             }
    43.  
    44.             var result = await Addressables.LoadAssetAsync<SpriteAtlas>(guid).Task;
    45.             if (result != null)
    46.             {
    47.                 if (!_loadedSpriteSheets.ContainsKey(tag))
    48.                 {
    49.                     _loadedSpriteSheets[tag] = new List<SpriteAtlas>();
    50.                 }
    51.  
    52.                 _loadedSpriteSheets[tag].Add(result);
    53.                 _guidToSpriteSheet[guid] = result;
    54.                 Log.Debug("load " + result.name);
    55.  
    56.                 if (_lateBindingCallbacks.ContainsKey(result.name))
    57.                 {
    58.                     _lateBindingCallbacks[result.name].Invoke(result);
    59.                 }
    60.                 else
    61.                 {
    62. #if !UNITY_EDITOR
    63.             Log.Warn("no callback registered for spritesheet " + result.name);
    64. #endif
    65.                 }
    66.             }
    67.         }
    68.  
    69.         stopwatch.Stop();
    70.         Log.Debug("sprite loading took " + stopwatch.Elapsed);
    71.     }
    72.  
    73.         public void UnloadSpriteSheets(SpritePreloadTag tag)
    74.     {
    75.         Log.Debug("release sprite sheets: " + tag);
    76.         if (_loadedSpriteSheets.TryGetValue(tag, out var sheets))
    77.         {
    78.             _loadedSpriteSheets.Remove(tag);
    79.             foreach (var s in sheets)
    80.             {
    81.                 foreach (var kvp in _guidToSpriteSheet)
    82.                 {
    83.                     if (kvp.Value == s)
    84.                     {
    85.                         _guidToSpriteSheet.Remove(kvp.Key);
    86.                         break;
    87.                     }
    88.                 }
    89.  
    90.                 Addressables.Release(s);
    91.             }
    92.         }
    93.         else
    94.         {
    95.             Log.Error("no sprite sheets to unload for " + tag);
    96.         }
    97.     }
    98.  
    99. }
     
  5. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282