Search Unity

Does SpritePacker pack sprites when making assetbundles?

Discussion in '2D' started by sonee, Dec 10, 2013.

  1. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    We're going to make assetbundles to reduce app file size, I wonder that sprites that will be included in assetbundle are going to be packed automatically when making assetbundles. We want most of sprites to be distributed from assetbundle.
    As far as I know, the SpritePacker works when only playing or building.
     
  2. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Yes it does pack sprites when making assetbundles.
     
  3. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    Thank you for answer.
     
  4. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    I created an assetbundle which contains lots of sprite then checked the assetbundle file inside. But there was no any atlas file inside the assetbundle. The assetbundle file was in Library/AtlasCache.
    Because assetbundles are mainly used to extend game contents, I think the atlas file must be in each assetbundles.
    I tried both prefabs only which have a SpriteRenderer component and textures only which have sprites as its children when making assetbundles.

     
    Last edited: Dec 12, 2013
  5. giyomu

    giyomu

    Joined:
    Oct 6, 2008
    Posts:
    1,094
    I have same issue , if I do not put the atlases file with my prefab object , I just get my 2d character without any sprite on it
     
  6. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Are you adding sprite objects to your asset bundle? Or are those atlassed sprite objects at least referenced by something else that's being added to the bundle?

    Adding a texture to the bundle won't pull in its sprites or the atlas.
     
  7. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    I tried to make an assetbundle with only prefabs that have a SpriteRenderer component referencing a sprite located in other path(not under Resources). But the assetbundle contains Transforms, Sprites and Textures, not any atlas textures. As far as I understand, there should be any atlas file.
    I tried several times changing BuildAssetBundle's options, but couldn't find any atlas file inside the assetbundle. It looks that atlases are only included in the final package file.

     
  8. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Atlas files *are* Textures. There are no extra explicit files needed. Whatever is in Library/AtlasCache is just a cache and will never be in a bundle.

    Can you submit a bug with a repro case where this is failing please?
     
    Last edited: Dec 12, 2013
  9. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    In the texture directory, there were just original textures, no any texture files named new. But the atlases were in Library/AtlasCache only. I think the files in Library/AtlasCache should be included in the assetbundle.

    Let me submit the bug report. Thank you for the answer. :)

     
    Last edited: Dec 13, 2013
  10. bryan_lee

    bryan_lee

    Joined:
    Apr 9, 2013
    Posts:
    3
    wait unity programmer solve this problem, use packing tag is nice to batch, but can there is a way to load custom atlas not use unity sprite editor(sprite editor is hard to use, I like to use tool similar with zwoptex or texture packer), this way , we can easy load sprite from texture in bundle
     
  11. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Sure you can use any third party app to create an atlas and then write a script which would convert the metadata produced by that app to Unity's SpriteMetaData. Just set your texture type to Sprite and sprite mode to Multiple.

    See here:
    http://docs.unity3d.com/Documentation/ScriptReference/TextureImporter-spritesheet.html
    http://docs.unity3d.com/Documentation/ScriptReference/SpriteMetaData.html
    http://docs.unity3d.com/Documentation/ScriptReference/AssetPostprocessor.OnPreprocessTexture.html
     
  12. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    This issue has not been solved yet(I've not tested in Unity 4.3.3)
    The main reason why we use the Unity2D is that we can utilize features supported by the Unity Engine like assetbundle.
    As everyone knows, the assetbundle is for extending contents dynamically.
    According to the document, atlases are built when building, not building assetbundles. This means that we have to make a final package always when extending contents like adding sprites for batching. If so, the assetbundle is useless.
    As I posted, I've checked several times inside assetbundle files. There was no any atlas file. If so, where is the atlas file for the sprites that newly added from assetbundles? The atlas files are generated automatically when loading assetbundles?
     
  13. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Atlases are also built when building asset bundles. You should notice the progress bar.
    If you want to get the atlas texture from an asset bundle, first extract the packed Sprite and then access Sprite.texture property. It will point to an atlas texture, not the original sprite texture.
    The atlas texture itself is not enumerated by the asset bundle and you won't find it when calling AssetBundle.Load.
     
    Zinov likes this.
  14. sonee

    sonee

    Joined:
    Sep 2, 2012
    Posts:
    18
    The answer is what I exactly want to get. I didn't know atlas textures are not enumerated. Thanks!

     
  15. Newcomma

    Newcomma

    Joined:
    Feb 10, 2015
    Posts:
    89
  16. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    There is no such concept as an "atlas" to the runtime. The same sprite object simply references a different texture.
    If the code provided on that page works, use it :) but I can't see why it would work.
     
  17. Newcomma

    Newcomma

    Joined:
    Feb 10, 2015
    Posts:
    89
    So perhaps "atlas" isn't quite the right terminology. By Atlas I mean, the Texture SpritePacker generates upon building.

    My issue is the following:

    I have a bunch of swords (sprite images) that I pack into an Atlas for both memory and runtime performance (batching a sword selection menu). I want to increase the number of swords in this atlas, potentially an infinite amount (of course not really infinite, but it might be 10, might be 100).

    At runtime when I show this sword selection menu, what I really want to happen is the following pseudo code:

    - Get SpritePacker TextureAtlas of swords 'unity_spritepacker_generated_swords.png'
    - For all sword sprites in Texture Atlas (normally represented by some UV array?) create all sprites by enumerating and iterating over them
    - Make a new UI rect for each sprite to display in the UI

    This relies on being able enumerate the Sprites contained within the SpritePacker generated texture, which I can't find a way to do. An alternative is to manually list all sprites in an array on an object somewhere, but to be honest this will be painful to maintain as the number of swords grows/shrinks etc.

    As most texture atlas' come with a seperate descriptor to list all the items it holds, I would assume some similar internal representation exists for Unity SpritePacker Texture that maybe isn't exposed?

    Any thoughts would be much appreciated.
     
    Last edited: Mar 18, 2015
  18. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    Currently the expected workflow is to keep a reference to every sprite you intend to use in your game.
    If you have a 100 swords and you pack them, you will need to track those references. SpritePacker is a convenience "things get packed behind the scenes automatically" feature and has no way of listing sprites per texture at runtime. That information simply does not exist.

    Most externally written sprite packers don't work exactly as Unity's core works and therefore track lists of sprites themselves. Built-in packer doesn't, but you can implement this behaviour yourself quite easily by running an editor script which stores all sprites with a certain packing tag in an array on some object, and then referencing sprites from that object at runtime - saves you the manual work. Though you must carefully handle atlas pages (multiple textures per atlas) in such situations.

    Ping @JuhaKiili @Veli-Pekka.
     
  19. Newcomma

    Newcomma

    Joined:
    Feb 10, 2015
    Posts:
    89
    Thanks for the response, your suggested solution is sensible and I'll implement it this way.

    I would say that being able to do this directly within Unity and SpritePacker would be ideal, but understand that the underlying implementation details (and/or intention) may make this problematic.
     
  20. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    It's not hard to implement for us, however there is a workflow issue - atlases themselves are not objects, so how would you tell unity which atlas to enumerate?
     
  21. Newcomma

    Newcomma

    Joined:
    Feb 10, 2015
    Posts:
    89
    Simply by using the same packing tag string, this should uniquely identify all atlas' (even if they're seperated into pages) and some API call would return them as an array, which can then be further enumerated.

    Atlas[] atlasses = SpritePacker.GetAtlassesForTag(string tag)
    Sprite[] sprites = atlasses[0].GetSpritesFromAtlas();
     
  22. TomasJ

    TomasJ

    Joined:
    Sep 26, 2010
    Posts:
    256
    But then we need to somehow know when to load the atlas and its metadata. The rabbit hole goes deep :)
     
  23. Newcomma

    Newcomma

    Joined:
    Feb 10, 2015
    Posts:
    89
    Some quick ideas:
    • GetSpritesFromAtlas() could internally load if it's not already loaded in the scene. Either it gets loaded by the first sprite instance that references/uses it, or at this point.
    • Alternatively, Load function on the Atlas class, Atlas.LoadAsync/Sync().
      • Danger here being that load needs to be called (I'm not a fan of non-RAII patterns, which this kind of would be). I don't know if internally you guys have some normal approach for this kind of access?
    • Atlas class constructor could also load on instantiation, potential performance bottlenecks if devs aren't careful, but then similar to calling Resource load on a Texture2D (or load on GetSpritesFromAtlasCall).
    • Some sort of wrapper class which is only responsible for loading/reference management of the textures and then SpritePacker -> AtlasLoader -> Atlas -> Sprites.
      • Perhaps this amount of indrection isn't perfect either.
    I guess the short answer is I don't know for sure what would be best :) but I think the potential difficulties are outweighed by the functionality gained. It would also allow dynamic (asset bundled) updates of just the packed texture without needing to also update the object that is recording them via the editor script you suggested.

    I reckon you guys are awesome enough to reach an appropriate solution. It would be really valuable for our project.