[OFFICIAL] Feedback request: API to Access Sprites in Atlas

Hi Friends,

I’m talking about this: https://feedback.unity3d.com/suggestions/allow-access-to-sprite-packer-atlas-to-retrieve-sprites-by-name
So we could do this:

 // get specific sprite by name
var sprite = myAtlas.GetSprite("oneOfTheSprites");
// or iterate them
foreach(var sprite in myAtlas)
{ /*do something*/ }

Trying to understand this request since it keeps coming up persistently. The point of a the SpritePacker is to group related textures to reduce draw calls.

Say you have AsianFurnitures tag and all your Asian style furniture go into there. In all likelihood you will render an Asian room with Asian chair, table and couch. This is efficient.

What you wouldn’t do is to group all the couches into a Couch atlas so it would contain the AsianCouch, VikingCouch, MayanCouch. By doing this, rendering the Asian room will require the CouchAtlas, TableAtlas, ChairAtlas. This is not efficient and defeats the purpose of SpritePacker.

But you might want to have a list of all couches for your in-game store so you could let the user browse through and buy the couch.

My question to you is: Do you want to iterate the list of Asian furnitures or do you want to iterate the list of all couches?

If all you want is a list of all couches for logical use, the SpritePacker is IMHO the wrong tool to help you build that list. It is really meant for optimization.

Please help me understand your needs. Thanks!

(a nice feature would be to be able to name sprites quicker, right now it takes ages to click on each one in the sprite editor, also you end up accidentally moving some when you click on them. Would be nice to have arrowkey navigation here or be able to name them in the Project window rollout triangle)

Basically, I have given up on naming sprites individually, as it is a laborious process.

Tags as I understand it, are to help you load sprites by theme, and negate loading textures into memory that you won’t be using.

So Asian Furniture would make sense, if you are in the asian house on the asian level. I guess this also leads to the assumption that you could say “tag name”.“sprite name” to get a sprite. If you can’t do this already?

To be fair the current process is to make some public fields on a prefab, drag in some sprites and reference sprites by var name / array index using enums OR put prefabs with sprites on them in the Resources folder if I want a sprite change in code, which negates the tag process entirely.

1 Like

I haven’t used atlases or multi-type spite imports yet, but it seems to me that the use case for being able to get sprites by name out of an atlas is to be able to use them as though they were not part of an atlas. Being able to assign things in the inspector is great, but you have to be able to address things in code too imho. If you can already do this then I am missing the point of the request.

Having looked through the unity scripting docs I did not find a SpriteAtlas class, which I honestly expected to find after finding Packer.atlasNames. I don’t understand what the atlas name would be for if you can’t then address an atlas with it.

Anyway, if we can’t get references to individual atlases and then sprites within them then, yeah, I would think this should be implemented. I was considering using them to grab assets out of such that an atlas of like things could be loaded via asset bundle and addressed via names taken out of a json manifest where the names of the sprites would only be known at runtime.

@iwaldrop_1 : I don’t think “use them as though they were not part of an atlas” makes sense though. Atlasing is supposed to be done based on usage patterns - sprites that are on-screen at the same time as each other sharing an atlas - so, trying to pretend that the sprites are not atlased is sorta directly opposed to that. If you’re accessing sprites completely randomly then you may even be better off not atlasing them at all; atlasing sprites badly might still save you a couple of draw calls but it wastes a ton of memory.

Could you give a more concrete example of what you mean by ‘like things’ for your game?

I am one of the up-voters for this feature request. Chiming in here…

Yes, atlasing should be done based on the expected usage pattern of the sprites in the game, i.e. collecting sprites that will show up in the same area / at the same time into the same atlas; it’s up to the developer to assign appropriate packing tags to achieve this. Ostensibly the goal is to keep as few atlases as necessary loaded in the graphics card at a time for faster lookup by the GPU (please correct me if I’m saying something wrong here I’m no graphics expert).


This issue is about being able to access and assign/switch sprites at runtime. Normally (?) this dynamicism is achieved in code by placing sprite assets into the Resources folders and calling Resources.Load(“path_including_folders”) but when they are auto-packed with Unity’s sprite packer you can’t grab the sprites anymore by name unless you store a reference to them via a prefab, etc.

For example, in order to use the atlases auto-generated by Unity I made a prefab with a few lists of UI.images exposed to the editor (I have multiple list to for organization’s sake, it’s akin to how I would use subfolders in a Resources folder to organize sprites and deal with name collisions). I have to drag and drop each image into a slot which is a very manual process as opposed to keeping the images organized in Resources folders and subfolders. I have this singleton (ugh) manager script on my prefab to then get the images in code and work with them as I see fit::SpriteManager.cs · GitHub

It would be nice to have access to the atlases/sprite directly, although perhaps there is some black magic there to cover cases where you have more images with the same packing tag then will fit in your minimum atlas size (actually I would love some clarity on what exactly these ‘pages’ are in the sprite packer editor window, are there multiple atlases under the hood the get pushed into the GPU together if possible?)

Hope this is clear but if not, @ColossalPaul please follow up directly with me in the Unity slack channel my nick is arun02139.

Cheers!

One of my concerns with this feature is it essentially makes sprite lookups a dynamic process… scripts could do things like “atlas.GetSprite(a + b + c)” making it impossible to determine whether a sprite is being used by the project or not.

If I understand things correctly, the current sprite packer will literally tear an atlas to pieces; so that the individual pieces can be put back together into a more efficient atlas (using packing tags). A dynamic lookup mechanism would surely make it impossible for Unity to determine whether or not a sprite asset is being referenced… and thus you would be forced to pack ALL sprites, even the ones that are not actually being used.

I am not sure how much of an issue this would be; but, there are almost certainly projects out there where people are taking advantage of the existing feature.

When it comes to asset files, Unity generally determines which things are in use and which aren’t based upon references made in other assets or scenes (or just being inside a “Resources” folder).

Given the above; my vote would be against complicating things.

If people are looking for named sprite lookups, then perhaps the better answer is to just create a data asset which maps sprite assets to unique keys. I created an open source asset called Ordered Dictionary Asset for Unity (available from Bitbucket) which makes this very easy to accomplish:

With this approach it also becomes trivial to create multiple aliases of the same sprite; this can be extremely useful for the prototyping stage where you just want to block things out using the same sprites. It becomes effortless to remap all the sprites without any clunky fussing around in the sprite editor.

2 Likes

Ah I hadn’t thought about the aspect of not-including unused assets in the build, you make a good point. But wouldn’t this kind of solution require dragging and dropping the images into the editor slots? If I have 150 small images that I want to be able to dynamically assign to different UI.Images (which I do) I really don’t wanna have to do this… ^^;

My list implementation allows you to drag and drop a whole selection of sprite assets from the project window and drop onto the list control. The keys are automatically grabbed from the sprite sub-asset name.

Aside: Of course, my list control isn’t JUST for sprites; it can be used for any assets or non-assets! The key and value of each entry of the ordered list can be anything that Unity’s serializer can understand.

1 Like

Accessing the sprites by name is not my primary wish. I would like to have some kind of an atlas asset, which allows me to get all the sprites in it, so a list or array of sprites would make me very happy :slight_smile:

I would like to use sprites for my Decal System. The idea is that the user selects a Decal System, picks an atlas asset that is supposed to be used for it and can place decals based on the sprites. This has the advantage that the user can only pick sprites from a certain atlas to keep the draw calls as low as possible.
If I create an application where the user can place decals at runtime, I need a way to iterate through the sprites to show the user what is available. This is not trivial to achieve at the moment, but with an array or list of sprites within an atlas asset, it would become very simple.

For the sake of simplicity, I consciously avoided things like what should happen if a sprite is removed from an atlas or moved to another one.

As I understand it’s requested mostly to avoid adding sprites manually to some serialized field before building, when you want to set sprites dynamically by name in runtime (like smiles etc).
Sprite packer is adding all sprites with tag to atlas anyway, either they used or not, so it looks redundant to save sprite names additionally.

I just need to be able to swap spritesheet at runtime.

I completely agree with numberkruncher’s post. I personally do not want these new atlas APIs if it means changing the sprite packer to be something other than a memory/draw call optimization tool.

I use ScriptableObject assets to organize sprites for things like sprite animations or other contexts that require dynamic lookups. Super simple and works like a charm :slight_smile:

1 Like

Sprite packer doesn’t check if a sprite being referenced or not - it just packs everything which has a packing tag set. And looking at how it works now (completely independent of the build process where unity “resolves” assets usages) I don’t think it’s going to be changed.

Hi,

Thanks for all your feedbacks. To be honest, this is not the first time I’ve ask this questions to users, but it is the first time I’ve ask this forum.

So help me check my understanding.

What I seem to be getting consistently is -

In wanting that, a lot of uses will immediately gravitate to the first and most obvious implementation which is

So my question is, do you really care that the list of sprites came from the atlas? What if there is a tool that could automatically help you manage your lists of sprites automatically? Would that be enough?

If you actually don’t care about how it is implemented, but you really just want an automated list management system, would you consider using a different solution, something like this:

(Labels as described in here Unity - Manual: The Project window)

Now this idea doesn’t work yet obviously. All i’m trying to get at is to find out the root of your request. So is it really accessing the atlas or you want an automated sprite list management system? Please share…

Ok so, I will just describe a simple use case that hopefully illustrates my issue with Unity’s sprite packing solution:

I have a game where when a unit is active, a ugui widget appears showing a detailed portrait of the character. This fairly high-resolution portrait (512x512) is based on the unit’s ‘job’ and sex (think Final Fantasy Tactics). What I am used to doing is dynamically assigning the correct sprite to the widget’s UnityEngine.UI.Image.sprite string field in code with the enum JobType.ToString(). I use texture packer to make my atlases now and it’s worked out great – with Unity’s sprite packing solution, I need to use a prefab and an extra script (see the gist from my first post in this thread) to keep the references and assign the portrait dynamically. I don’t want to do that; it’s extra manual work and what if my enums / job names change?


This is really an aside to the main point of the thread, but there are lots of different possible combinations of jobs, and in the future I plan to build the atlases on the fly (i.e. in the scene before the battle scene after the troop configuration is determined) to minimum the number of atlases needed in memory during battle. It’s also likely that additional portraits will be downloaded on demand in the future without requiring an app update. If I do this, I will need a way to dynamically grab the right portrait in runtime – any ideas on what the code flow might look like?

Thanks in advance :wink:

That’s what I understood as well, you are mostly interested in an automatically maintained list. It’s not really about what’s in the atlas. Yes?

Because I could think of many reasons why a sprite could appear (logically) in multiple lists. Like shoes.png for a character that could appear in the character’s list AND also the in-game store list.

But with “get assets from atlas”, this could only come from one of the list. How would you satisfy the need for an interable list that serves both your character AND you in-game store.

But, if you imagine with my Label idea, you could apply 2 labels to the ‘shoe.png’. You could put a “character_clothes” and a “store_item” labels on them. You could then use some API to get at the shoe.png by querying for sprites with either character_clothes or store_item. Doesn’t this match your gameplay/logical use cases for automated list management better than atlas could ever hope to?

When we make our games (Kingdom Rush series) in order to fit in low memory devices we sometimes need to make custom atlasses for some levels.
So for example, in levels 1 to 5 we are using the “WoodsEnemies” atlas, and on levels 6 to 10 we use the “DesertEnemies” atlas.

but then after that we make an expansion, that happens in the frontier of those terrains, and have a few enemies from the woods, and a few enemies from the desert. Loading both atlases wont fit into memory, so we need to make an “EpansionEnemies” atlas that cointains a few enemies of each.

so we cant just point at one sprite in our enemy prefab, we need to reference the animations by name, that means referencing the sprites by name, and we dont want something solved at build time to map our enemy to the atlas or sprites needed. We want to just be able to load the proper sprites, and if we did our work right, then the needed sprites will be available for the enemy to be animated.

We were able to hack 2dtoolkit to get that working in one of our projects (loading texturepacker sprites, and hacking the 2dtoolkit sprite component to run in editor and at runtime, and load by name the sprites).

This behavior is the exact thing you get when using something like cocos2d, or libgdx, the developer is responsible for loading the atlases (this means that now there are a number of sprites available to be queried by name), then you define the animations as a set of sprites, and then you just use the sprites. There is a king of late binding of sprites to atlases that allows us much more control over our game.

In another of our games, we have text files in a key value format to define skills for units, and one of the things we define there is the name of the Icon that the ability will have. Being able to just do sprites.load(iconname) and have that just work as long as I loaded the proper atlases would be ideal.

Hope anything of this makes any sense, and feel free to ask for more info if needed

Rubén

1 Like

In my case I don’t care where a sprite come from - having a list that would allow me to query a sprite by name or by label as you suggested would be great ! If applying label could be done on a single Sprite or Sprite packed into an Atlas then it would be perfect :wink:

not sure how I feel about this. It makes some sense but also it makes it unintuitive to use for people that are not as resource strapped. Having to know what to load in order to use something is creating a an extra coupling. You will inevitably create a sprite<->atlasToLoad table and writing a lot of loading/unloading code.

This is just a generic list use-case not a atlas specific one.

I would still like to hear more use cases if anyone care to share… Not just in Unity but also in other engines or previous projects…

It sounds like the main clear use case that has emerged so far is ‘being able to swap a whole load of Sprites in one go,’ for character reskinning and so on.

The way you guys are used to doing it is to name all your sprites in a predictable way (e.g. ‘walk_down_1’ and ‘walk_down_2’ in the base skin, ‘walk_down_1_blue’ and ‘walk_down_2_blue’ in the blue skin) so you can easily loop through all the sprites, calculate the name for them, and bind the new Sprite through looking it up by name in a ‘per-skin’ atlas.

Does that sound about right?

It sounds very much like a use case that is not exclusive to sprites and needs to be easily solvable in Unity in general. I think the way I’d do it at the moment is to use AssetBundles, but the experience there is not yet as smooth as it needs to be yet…

3 Likes