Search Unity

Unity 4.5 Sprite Packer does not pack images inside Resources folder

Discussion in 'Editor & General Support' started by iPicnic, May 27, 2014.

  1. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    The comments I have made (that weren't my own suggest solutions) are all from direct feedback/discussion with Unity devs and staff. None of it is trade secret or proprietary. But I do feel that it is beneficial to share the elements that I can, at least until the docs get more robust and up to date. And again, Unity is working on this stuff, and I realize they have a ton on their plate. I definitely mean no disrespect or slight to them at all, but I really feel that it will be a great service and benefit to all developers once they are able to communicate more broadly best practices.

    There is a bit of... discomfort(?) sometimes, being an active member of this community, and also being an corporate client with ties and access to Unity, for two reasons. First, seeing people struggle with things like the resources folder, where the docs don't reflect effectively the current state of things. Working with Unity, in some cases, they will be able to quickly respond with something like, "oh yea, ignore the docs, it works like this...", or some useful gem that isn't documented. Sure, great for us, but I would love to see this stuff shared more broadly. And second, without exception, every single unity staffer I have met, regardless of role, is passionate and proud of Unity and what they are doing, and they are aware of the challenges they face. (sure, there may some jerks that work at Unity, I just have been fortunate enough to not encounter them) So I do get a little defensive when people bash on UT staff or their motivations unfairly. (not in this thread).
     
  2. Disastercake

    Disastercake

    Joined:
    Apr 7, 2012
    Posts:
    317
    Thank you very much for taking the time to explain that in more detail, @zombiegorilla. That makes more sense where you're coming from now. I wish that Unity opened up the docs for potential community management (or just suggestions) if it's so far behind and difficult to manage by themselves. It sounds like it could really need it.

    Do you have any idea when "Resource Management in Unity 5 : The Definitive Guide" will be releasing? I really want to give it a good look over and start figuring out how asset bundles can be used well.
     
  3. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Our draft is from last month. We were told that it was largely finished and going through translations and that it was nearing completion. Beyond that, no clue. It does state that it is designed for 'advanced Unity programmers', so it is a high level overview. (no code samples or anything, and assumes the reader understands the concepts). But it really clearly explains the different flows, best practices, alternate methods based on needs and optimization techniques, pitfalls and strategies. I really, really hope that they do a ton of guides like this on other topics, it is really well written and covers so much.
     
  4. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    Well, the array list of sprites on a prefab works I suppose. I just loop over the array and stuff them into a dictionary based on name. I then blow away the array unless I need them for something like the character creator. The textures that are added to that array prefab have a packaging tag and they do work in the atlas.

    I get the angle on how Unity is trying to make the atlas transparent. It works, if your design uses a unique prefab for every object that might exist in your project. If you don't have a sprite texture on any prefab anywhere but want to use it later, you are basically boned and have to hack in something like the sprite list on a prefab. Can't say I really like the system. It seems to break the concept of keeping assets separated from data structures (in this case prefabs). But I suppose Unity considers they should be one and the same?
     
    Last edited: Mar 2, 2016
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    No, you just use a ScriptableObject.

    It beats hard-coded strings and paths.

    --Eric
     
    zombiegorilla likes this.
  6. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    Huh, I just see the sprite on a prefab as "hard coded."

    The real issue is serializing my game data to json and the lack of Unity to call a sprite by name from a dictionary. I opted for the json serializer for its support of dictionaries. I also like the ability to check the raw json. Anyhow, the ability to pull a sprite by name from an atlas is the second most voted feature in the 2d section. Perhaps one day.
     
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Having a reference is the opposite of hard-coded, since you can change anything (texture, name, location) and stuff will continue to just work without having to remember to update or change anything else. Also, you don't need it on a prefab.

    --Eric
     
    zombiegorilla likes this.
  8. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    Oh, I get that. It just seems "hard coded" when you can't change the sprite without having another reference sitting around somewhere. That is what I mean.

    So, if I have a single prefab which all my units use. If I want to change the sprite displayed on that prefab. How do I go about changing the sprite? Before the scene loads, I do not know what creatures will be spawned. Is the design flow just to create a prefab for each unit?

    I'm trying to understand how the developers expect someone to use Unity. I attempted to create a single prefab which would be modular in its use. Is this not the way to do it? Do I create unique prefabs for every unit? Is the modular ability only in the script(s) that is attached to a prefab?

    How do I grab a sprite using code that is not already on a prefab or scriptable object without using Resources.Load? Resource.Load only works for assets in the "Resources" folder correct?
     
    Last edited: Mar 2, 2016
  9. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Ah, but that is the beauty of using references over names. If you change a Sprite, all references in your project are 'updated' because they pointers. The asset database handles that. Also it works backward, you can find references all references in your project. Using just a string loses a lot of useful functionality that is built in.
     
  10. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    I already make changes to my sprites and they change even while I'm running the game in play mode. I don't have to change the string name ever once my record is setup.

    I'm not following something. If I don't know what sprites will be used for a given encounter in my game I should just create references to all the sprites using either a prefab or scritable object. And then just call the reference from there?
     
  11. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    I'm a bit stuck if I can't use json. All my units are saved as records in a json file. Units have your standard attributes such as health and name. But they also have generic lists of strings or structs for things like actions they can take and effects (buffs) they may start with.

    It would be possible to create a prefab for each unit and then save that prefab name in the json file. The reference to the sprite would then be outside the json records. I would have to use Resources to grab the prefabs or create a prefab with an array holding all the prefabs.

    So, you guy would only suggest using scriptable objects and create custom two array classes (key, value) to simulate dictionaries? All for the Atlas... heh.

    If anyone is still reading this far into the thread here is a scriptable object tutorial.
    http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects
     
    Last edited: Mar 2, 2016
  12. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    There is no single answer for that, it would depend on your architecture and design. I would think that you would have general idea what would be needed at a given time. If for no other reason to have a level of control over your atlases. If you end up having to pull 1 sprite from each of 50 atlases, things will get ugly fast. At that point atlasing is counter productive, using single textures would more performant.

    But generally, if you are talking about a ton assets, a cms sloution like json/xml/etc is your best route. All of our content is remote, (many thousands of assets, multiplied by 3-4 platforms). Everything is assetbundes, and json is used by the client to track them. (the json is generated by a database which actually manages all the references).
     
  13. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    You can reference the sprite in your json doc. Unity's serializer will contain all the data that it needs for standard Unity classes. (basically the meta). A serialized ref to a sprite will have the uid and such pointing to the asset in the assetdatabase. (though it could break if your assets are in a resources folder).
     
  14. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    It really depends on your goal. I use SOs a lot, but primarily for pluggable data sets (and editor tools). I use dictionaries in SOs often. You don't need to simulate them, you just have to take an extra step of serializing them, as they don't serialize natively.

    But the main thing is matching a solution to your actual need. If the goal is just to be able to arbitrarily load a sprite based on an uber collection of sprites, then the simple way is assetbundles. make a "sprite" bundle, tag all the sprites you want to use in the project and you are there. (making sure they have unique names.) You can view a list of them, and/or load them by name.
     
  15. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    I can adjust my objects to be stored inside a Scriptable object list. Did a quick test and it seems to work fine with the editor and at runtime. Phew. Thank you.

    Just out of curiosity would it be possible to do something like save an asset guid and then load that asset at run time based on the guid? Not sure if that is how AssetDatabase.GetAssetPath and AssetDatabase.AssetPathToGUID is supposed to be used or not.
     
  16. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    I Doubt it, at least not directly. Those are UnityEditor classes, so not available at runtime.
     
  17. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    Yeah, I wasn't sure if there was a different way of accessing an asset in that manner at runtime. Thanks again.
     
  18. Disastercake

    Disastercake

    Joined:
    Apr 7, 2012
    Posts:
    317
    That's unfortunate there won't be example code. Example code is often much more useful that walls of text and theory. Perhaps since you're involved in this document you could convince them to supply some example code to help support the documentation. At least a preliminary glossary of links to other tutorials that help support the required foundational knowledge would be more helpful than none. It's not going to be as useful as it could be if there isn't available tutorials and information to bridge the gap between the current documentation and this new one, especially if there's no example code snippets to glean from.
     
  19. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    I'm not involved in any way. We were just provided early versions as we were in the process of switching our game over to 5 and unity was helping us get trough it as smooth as possible. The final version may have additional content, really don't know. But, It is very much a high level view of how things function under the hood, not a tutorial or how-to. More of a resource for design.
     
  20. MaxEden

    MaxEden

    Joined:
    Jun 22, 2013
    Posts:
    82
    I talked about the sprite itself, not the sprite renderer or whatever. The sprite itself will be loaded in the memory as any referenced asset or prefab, at the moment of deserialization of the object that contains it - instance of scriptable object.
    And considering that sprite type contains a property
    Code (CSharp):
    1. public Texture2D associatedAlphaSplitTexture { [WrapperlessIcall, MethodImpl(MethodImplOptions.InternalCall)] get; }
    I'm pretty worried that there is no any lazy loading implemented.
     
  21. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Nope. The texture asset of the sprite is loaded into memory with instantiated (placed in the scene). Like any other asset. Should be pretty obvious, otherwise prefabs, scenes, pretty much everything would break down pretty quickly. ;)

    What will affect lazy loading (to some degree) is atlases. The whole atlas will have to be loaded to use the sprite, but that is kinda the point and the trade off for using sprites.
     
  22. MaxEden

    MaxEden

    Joined:
    Jun 22, 2013
    Posts:
    82
    That's not true.
    Instantiation is a basically cloning of already loaded asset through serialization. The whole asset with all its dependencies loads in memory much earlier than any instantiation could happen.
    The point is, when you have access to the scriptable object, you already loaded all its dependencies including textures.
    If you have one global scriptable object with all the sprites, and have any access to it through the whole lifetime of your game, that means you load all the textures and keep them loaded even if they never used.
    People should keep it in mind when they make global objects with references.

    Loading the whole atlas texture when you use only one sprite is understandable, loading all the unnecessary textures and not using it is a different thing.
     
  23. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Definitely not the case. Try it. Add a script to a scene that has a public Sprite[] (or Texture2D[] or whatever) and fill up with everything you can find. Profile it.

    A reference to a sprite (game object, texture, whatever), won't impact memory until is actually loaded in to the scene. (well, except for the memory used to for the data that the prefeb/script uses, which is insignificant).

    Here is a quick example: First screen is empty. Second shows a script with public references to ~300mb of textures (30 x 10mb). (Note: the small difference accounts for the editor display, collapsing the inspector and they the are virtually identical.)
    Screen Shot 2016-03-07 at 12.39.35 PM.png
    Screen Shot 2016-03-07 at 12.39.52 PM.png
     
  24. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    That is only true if you are instantiating (cloning) an object already in the scene. Not the case when you are in instantiating a prefab. Instantiating a prefab builds a new object based on the prefab structure in project.
     
  25. MaxEden

    MaxEden

    Joined:
    Jun 22, 2013
    Posts:
    82
    Just made a test. Memory consuming is much less then I expected, but still it looks like it loads every single texture.
    Scene with no references on sprites:

    Scene with references on sprites:

    Note that after further creation of SpriteRenerers that use these references, memory consuming barely changes



    In which case? Every reference on the prefab loads whole prefab in memory. It's a hidden object, it's not a part of the scene, but it's still in memory and you can even manipulate it.
    Code (CSharp):
    1. public class SerializationTest : MonoBehaviour
    2. {
    3.     [SerializeField] private GameObject _prefab;
    4.  
    5.     void Start()
    6.     {
    7.         _prefab.transform.localScale = Vector3.one*0.1f;
    8.     }
    9. }
    Note that such code will change the prefab itself, even at runtime, even between scenes and scripts the changes will stay.
    You can only straightly deserialize something like when you load a scene, or instantiate it from a prefab - a reference object. The only way to drop loaded prefab object is to load scene without such reference or to call
    Code (CSharp):
    1. Resources.UnloadUnusedAssets();
    explicitly.
     
    andreyul likes this.
  26. bitbiome_llc

    bitbiome_llc

    Joined:
    Aug 3, 2015
    Posts:
    58
    Due to how I save game states and perform multiplayer messages and RPCs I'm using a hybrid system that uses scriptable objects where I can. But I still require a sprite dictionary with a string key. Is it possible to write a scriptable object to permanent storage at runtime? I fiddled with saving scriptable objects at run time but finally fell back to a json serializer for now.
     
  27. Zinov

    Zinov

    Joined:
    Jul 20, 2015
    Posts:
    38
    I wonder as well. Looks like a bug to me, because I see exactly zero reasons for it not combine sprites together under convenient Resource.Load interface. I too see the process of managing sprites references too "hard-coded" and thus it must be avoidable.
     
  28. -Aymeric-

    -Aymeric-

    Joined:
    Oct 21, 2014
    Posts:
    110
    Great read here! And thanks for all your comments @zombiegorilla.

    I'm deeping myself inside the SpritePacker tools, and I've some questions. Let say that my project is more artistic than a game. I've more than 1000 textures of 512 x 512, with combinaisons of animations like AA_01 to AA_22, BC_01 to BC_0-17 etc. So I packaged them via SpritePacker using my letters (AA, BC, AAB, etc.) for packing tag.
    I just need to display one Sprite at a time. I created an array of my Sprites via a ScriptableObject, it contains a reference to each Sprite so it's OK from a memory perspective?

    I've a lot of Atlas packed, let say 50. How does Unity load/unload them? How can I know which one is ready and which one is not?

    I assume that I can easily create a SpriteRenderer with an animation where I switch the Sprite to an other one in the same Atlas (all AA animated in my examples). But how to manage animations using Sprite from several Atlas? If Unity keep them all in memory, it will crash... if it loads them when needed, there will be many loading time...
     
  29. Zinov

    Zinov

    Joined:
    Jul 20, 2015
    Posts:
    38
    I recently discovered that you have to use Resources.UnloadAsset() for unloading public Sprite fields in this kind of Sprite list manager since they will remain in memory once the rendering system actually requests their instances out of your list.
     
  30. -Aymeric-

    -Aymeric-

    Joined:
    Oct 21, 2014
    Posts:
    110
    Well does it make sense to call Resources.UnloadAsset() on each Sprite when they are packaged via SpritePacker? Because this is not a simple Sprite in memory but a whole sprite sheet, right?
     
  31. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
  32. Disastercake

    Disastercake

    Joined:
    Apr 7, 2012
    Posts:
    317
  33. Zinov

    Zinov

    Joined:
    Jul 20, 2015
    Posts:
    38
    @zombiegorilla how do you manage to unload sprites from memory after accessing them through ScriptableObject list? I found that they will end up in memory if you won't play with Resources.UnloadAsset(). Tho, I haven't found the exact way to free them yet.

    Storing all the assets in a single object to access them dynamically is a good idea on paper, but I don't see how am I supposed to clear the memory hold by this object and its static public fields.

    So basically it's a tradeoff. If you want to get advantage of the awesome Unity sprite packer, you must not place textures under Resources folder, but at the same time you won't be able to access them dynamically without bloating your RAM.

    The behaviour of this system is not clear also. For example, I have public MonoBehavour which stores Sprite[] and its id's so I can access those sprites from code. When I start the game, this sprite holder doesn't allocate the memory for all of the sprites at once. But when I start referencing them in code, lots of them are ending up in RAM. So after I used them all and switch my screen to loading screen to clean up the resources, no matter what I call Destroy(texture), Destroy(Sprite), Resources.UnloadAsset(), nothing really frees the memory hold by those requested sprites.
     
    Last edited: Jul 19, 2016
  34. DaveCrowdStar

    DaveCrowdStar

    Joined:
    Nov 13, 2015
    Posts:
    13
    I think I may be missing something as well. Hopefully @zombiegorilla can help us. I have had the same experience as @MaxEden.

    If I have a prefab with references to 300mb of texture data, how do I load just one of those textures into memory without the others? When I try to test it in the editor with ios PlayerSettings, I am always getting all or nothing.

    I did not know it was possible to load a GameObject into memory without loading all of it's dependencies (and their dependencies all the way down the line). Is this only with ScriptableObjects? I do not have much experience with ScriptableObjects.

    TL/DR First question: How do you NOT have all Textures in a List<Texture> loaded into memory when GameObject/Component is sitting in the scene? I was unable to reproduce this (they were always loaded).

    Second:
    My second issue is that I too want to use a json. I have a reward message with some icon. That icon is used throughout the game. Say it's a potion, but it could also be a bag of gold. I won't know until I get a response from the server. Previously I was using Resources.Load and loading them into a Dictionary. That way, when the server tells me the reward, I have the reward mapped to the icon. They are also used throughout the game. You see that bag of gold everywhere. I didn't realize until today that images in Resources were not atlased. So what is my solution? Is it to have a prefab or scriptable object with a link to each reward sprite?

    TL/DR Second Question:
    What if I want to reference an image by string? I prefer the json from the backend to say "gold" rather than some id. Is the best practice to make a quick Dictionary in something like a "SpriteList" component?

    TL/DR Third Question: Why not double load the Texture? If I want it Atlased, I'll add a packing tag. If I want it as a texture, I'll call Resources.Load. Why makes these things exclusive at all? To protect me from Atlasing a Texture in the Resources folder???

    Very interested to learn the best practices. Hate the idea that I'm doing something the wrong way.
     
  35. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    What memory? If you are profiling in editor, it won't be an acurate reflection of the actual build. Profile the build. References to assets won't increase scene memory until actually used.

    Sure, it's up to you how you want to do it. You can also have an array and look them up by name.
    There is nothing wrong with doubling up assets that way. It's unrelated to the resource folder. You can have one in an atlas and one not. It's pretty rare that you would need that, as the point of atlasting is to group common assets that are frequently used together. If you have 50 icons where you only ever use one or a couple at a time, atlasting is more expensive. Atlasting is beneficial when you have several elements that always used together, like ui for example. Or something like 2d map elements, stuff like that.
     
  36. DaveCrowdStar

    DaveCrowdStar

    Joined:
    Nov 13, 2015
    Posts:
    13
    Thank you for responding @zombiegorilla . I'm always trying to improve my skills!

    I just did a build to my ipad with this and saw a substantial increase in memory. It shows exactly what I thought it would, 10 extra textures with an increase of 25 mb in RAM. These textures are never used, they are just referenced in a public List<Texture> (in a component I made called TextureList, just for this experiment) and that prefab is loaded into the scene. Maybe I should try a reference to a prefab which then references the textures?

    I have done this before and was surprised to see all the asset dependencies loaded into memory. One of the earlier projects I worked on had UI screens linked in a prefab which was referenced in the bootstrap and it caused all the game's screens to always be loaded into memory. In fact because of the way things were referenced, it was basically loading the entire game, because references in references were loaded, etc, all the way down. If a prefab referenced a prefab which referenced another prefab which finally referenced a texture, that texture was loaded into memory when the first prefab entered the scene. Even if the references were 100 levels deep and finally a texture at the end, that texture would be in memory. I would be super excited to find a way to reference Textures/Prefabs that did not load dependencies!

    This would mean I have to duplicate the image right? The original point of the thread was the reasoning behind not packing sprites in the Resources folder. Why not just pack any Sprite with a Packing Tag? I just don't see the point of making the folder prevent packing. If it's set as a Sprite in the inspector, why not pack it?

    Finally, I just want to get your opinion on resource management. I've gone through the best practices stuff that you linked. For the most part, we are already using asset bundles for 99% of our assets. The exception is UI, where it is built into the client.

    To be clear, you are saying that the correct solution would be to write an editor script that create prefabs or serialized objects which contain references to all the sprites and all the textures? Maybe also a lookup Dictionary. None of the images would be in resources. Would the prefab that references the Textures be in Resources? Then at runtime, check that map for the existence of the reward image, and get the correct Object. If it's a Sprite, convert it to a Texture (I need it as a Texture in case of the reward, but I still need it packed for the rest of the UI). And all of this is because we should not be using Resources.Load for individual Textures or for that matter anything?
     
  37. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Could be a few reasons. If you are comparing a build with images not in a resources folder, one referenced and one not, it will be larger, as if they aren't referenced they aren't included. Also it may be how you are putting them in the scene. A scriptableobject would probably make a difference. It's hard to say what exactly is happening. It also may depend on what "memory" you mean. But using references won't increase "memory" by itself.

    The folder doesn't prevent packing. Packing happens as normal. They are separate things. Anything in the resources folder is always included, that is its main feature. Images outside the folder that are packed are not included included in the build because they aren't referenced by the project, the references point to the atlas instead.

    You definitely should not pack (atlas) all sprites. Only pack the ones that make sense. Arbitrarily packing all sprites will most likely increase memory usage. Having a duplicate image for a sprite is useful in some cases, rare, but can be useful.

    How you do it depends on your needs. If you have a texture that is used as a texture, and a sprite either don't pack it or have two. Resources doesn't change that in any way. If you use it in an atlas, and have it in resources you have two. If resources did atlas and ignore the way packing does, then you couldn't use it as a texture. You still end up with two.
     
  38. DaveCrowdStar

    DaveCrowdStar

    Joined:
    Nov 13, 2015
    Posts:
    13
    I'm talking about looking at Memory in the Profiler (the section below Rendering and above Audio) and seeing the number of textures increase by 10 (the number in my list) and the number next to it increase 25mb (so it says something like Textures : 10 / 25MB, though that is the increase, i made a new scene not a new project ). These textures are in the resources folder. They are references in a List<Texture> via drag and drop on a component which is present in the scene. I made a special test for this, so nothing else is going on.

    Are you saying that sprites are packed into an atlas regardless of folder?

    I'm not talking about shipping the sprites into the build, I'm talking about packing them into an atlas. Anything with a packing tag will be packed into an atlas unless it is in the resources folder. Sprites in the resources folder are not packed into an atlas regardless of the packing tag. Someone on my team stumbled upon this looking at Window>Sprite Packer and saw that images in resources are not packed. He just moved their folder outside of resources, hit the Pack button and the Sprite Packer window showed the correctly packed sprites. This is what I'm going off of.
     
  39. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    You're profiling in editor, and still using resources folder, and putting them in an object in the scene. The resources folder isn't memory managed the same way assets in the database are. And profiling the editor isn't reflective of what an actual build is.

    References aren't getting loaded fully loaded into scene memory (when done properly), if that were the case, mobile development would be nearly impossible.

    Still not sure exactly which numbers you are looking at, so I did a quick test. Empty project + 12 3mb images. First column with them stored the normal way in a folder. Second they are stored in the Resources folder. First row is nothing in the scene except the default camera and light. Second row is a gameobject in the scene with a list containing the images. Third is the same, but with the gameobject being a prefab (just to check). The last is the scene with 12 quads with images on them (for comparison).
    resources_v_assetdatabase.png
    You can see there is virtually no difference except for the last one. But again, this is in editor, so many of the numbers are meaningless.

    This appears to be true, or more accurately, it is very unstable. I gave it a test and it worked just fine... a couple of times. If I changed anything, the atlas (packing) stopped working. I could fix it by dragging them into a proper folder and packing, and putting them back into the resources, but it would become 'unpacked' after a bit. Which makes sense, as the contents of the resources folder aren't tracked by the assetdatabase in the same way, and the references get rebuilt on on build/play. So, yea, if you want to use atlasing for sprites, you don't want to put them in the resources folder.
     
  40. DaveCrowdStar

    DaveCrowdStar

    Joined:
    Nov 13, 2015
    Posts:
    13
    @zombiegorilla

    I was profiling my iPad 2, and it was running from xcode. I wasn't profiling the editor.

    I did not use an empty project last time. This time I did. I again tested on my ipad air. I have 1 gameobject in the scene that contains a public list. This is the code:

    using UnityEngine;
    using System.Collections.Generic;
    public class TextureList : MonoBehaviour {
    public List<Texture> textures;
    }
    NoGameObject.png GameObject.png
    I built to my ipad twice and attached the screenshots. You can see that with no textures, I have 14 textures using 81kb of memory (I assume from the engine?) and with my gameobject in the scene, I have 24 textures using 24.7 mb. These are large textures between 1-2k resolution. What am I doing wrong? I would love to serialize references and not have them loaded into memory like this. None of the files are in resources, they are all under the top Assets folder (there are no sub folders)

    For the record, I also tried adding another layer and drag and dropping the textureList gameObject into another script. I tried both a public GameObject and a public TextureList.
    The result was the same, 24mb.
     
    Last edited: Nov 4, 2016
    lexacutable and nox_pp like this.
  41. Aithoneku

    Aithoneku

    Joined:
    Dec 16, 2013
    Posts:
    67
    Hi, I have similar problem as OP. I read this topic and it was said to use asset bundles instead of resources. Like other people here, I'm not sure how Unity wants us to use it, so I would like to ask whether following solution is correct;

    Original question (probably incorrect - see bellow for update!)

    Problem
    We have a lots of sprites which are used sometimes (different screens, different scenes). Until now all of them were referenced using Scriptable Objects, however the project grow up and game crashes on low-memory devices due to lack of memory. So we need to load them dynamically at runtime. (Already implemented the "incorrect" way, it significantly helped. The game now runs on devices which were never able to even start it.)

    Another thing is that lots of sprites are used together, so we put them into atlas, decreasing draw calls count. The project is gui heavy, so we're currently optimizing as much as possible to get some decent fps.

    Our original solution which is "Unity incorrect"
    1. Move sprites to Resources directory
    2. Create references to them in our game data (I implemented custom struct for that which can recover the reference if resource was moved/renamed - in editor only, of course)
    3. Load the sprite at runtime when needed
    However, sprites are not in atlases - as designed by Unity devs and discussed in this topic.

    Asset bundles solution, "Unity correct"
    1. Update sprites - assign them to a bundle
    2. Create references to them in our game data (I would implement custom struct for that)
    3. Load the sprite at runtime when needed
    4. Each and every single time we make a build, make also the bundle build
      • In the best case, make it somehow automatic step of the build, need to implement that
    5. Attach the bundle to the build
      • Need to figure out how to do that for each platform (quick Google search didn't help, need to do more deep research) - is there a documentation for that I missed?
      • In the best case, make it somehow automatic step of the build, need to implement that

    Is this right?

    Update

    (6. 12. 2017) Because of lack of any reply from Unity staff, I assume that what I wrote above is incorrect and the correct solution is in my post bellow.
     
    Last edited: Dec 6, 2017
  42. Aithoneku

    Aithoneku

    Joined:
    Dec 16, 2013
    Posts:
    67
    Original post

    Note to my previous post: before I'm confirmed or corrected, our current solution is following:
    • Create a Scriptable Object which keeps reference to needed sprite.
    • Put asset with this S.O. to Resources directory.
    • Put referenced sprite outside of this directory.
    • Load referenced S.O. using Resources system when the sprite is needed.
    This allows us load needed sprites indirectly on demand while sprite is kept in atlas. I checked on small testing project that the atlas is loaded only once. This is currently the most simplest solution how to save both memory and draw-calls in our project.

    Update

    (6. 12. 2017) Due to lack of any reply from Unity staff, I assume that this is the correct solution to the problem.
     
    Last edited: Dec 6, 2017
    nox_pp likes this.
  43. nox_pp

    nox_pp

    Joined:
    Dec 30, 2014
    Posts:
    4
    I haven't tried this, but this seems like a really good solution for those who are just trying to better manage memory use, and don't actually need to host their resources remotely. Asset Bundles are the most cumbersome feature ever devised.
     
  44. DaveCrowdStar

    DaveCrowdStar

    Joined:
    Nov 13, 2015
    Posts:
    13
    This does seem like a good solution for getting sprites from the atlas
     
  45. lexacutable

    lexacutable

    Joined:
    Jan 24, 2014
    Posts:
    8
    I'd like some clarification from someone who is familiar with this about how to 'do it properly', since moving a bunch of stuff into Resources IS the only way I have been able to get our game to fit in memory on iOS. If an object in the scene has references to prefabs, it seems to always (or at least very often) load the prefab's assets into memory immediately, not just when instantiated. This causes a giant pause on game startup and the game to run out of memory after a few seconds. The comments in this thread that assets aren't loaded until instantiated is very much contrary to my own experience.

    The only thing I can think is that I'm accessing the prefab's names in order to know what to instantiate when necessary - would/should this really cause the entire thing to be loaded?
     
    Last edited: Jan 11, 2017
  46. Aithoneku

    Aithoneku

    Joined:
    Dec 16, 2013
    Posts:
    67
    Me too.

    This is exactly same as my experience. The fact that the game stops crashing on low memory after we remove these references is proof that something is loaded somewhere.

    I read somewhere in Unity manual (regrettably, I'm unable to find it now), that textures (and other assets for video memory) are loaded to GPU when they're first visible, not when the scene is loaded. However, they are loaded in RAM when the the scene is loaded.

    My theory about contradiction you mention is following: people who are saying that "assets aren't loaded until instantiated/visible" actually mean "assets aren't uploaded from RAM to GPU memory until instantiated/visible" while people (like you and me) saying "assets are loaded as soon as something referencing them is loaded" actually mean "assets are loaded to RAM as soon as something referencing them is loaded".

    Of course, maybe I'm wrong. Maybe people who are saying that these assets are not loaded are using different Unity version or different (undocumented? hidden?) configuration.

    But for me, the hard, undeniable fact is that when I make a build, display empty scene with prefab / scriptable object references and connect profiler to the build, the profiler tells me that textures referenced by these prefabs / scriptable objects are loaded (not saying whether it's RAM or video memory). And when I reference too many of them, the build crashes on low memory.
     
  47. RavenTravelStudios

    RavenTravelStudios

    Joined:
    Oct 15, 2015
    Posts:
    100
    Sometimes i wonder why we have to use sprite packer instead of having something to manage the batching itself\.

    Let's say i have 10 textures. I draw all of them in a nested game obj. It makes 10 draw calls. Then i copy it again and again and i should still have 10 draw calls, not 10 * n.

    A draw call means a graphic change state, so for example by code i would be able to do something like:

    - Batch(texture 1)
    - Draw n of this texture
    - End Batch

    - Batch(texture 2)
    - Draw n of this texture
    - End Batch

    And so on, all still in 10 batched draw calls. That was possible in XNA, for example. But you can really do that in Unity only using atlas tag packing, and i can't see why.

    Neverthless, this would "fix" also the Resources loading problem. We would simply get rid of the atlas packer and draw our atlas grouped by batching up to us. I can get Resources folder isn't supposed to be the "main" way to load assets, but if you look around a LOT of people actually use it for this purpose, because it sounds and it acts like it was built for this.
     
  48. RavenTravelStudios

    RavenTravelStudios

    Joined:
    Oct 15, 2015
    Posts:
    100
    To make a real example:

    Here's a gameobject with 10 nested sprite renderers, each one rendering a different atlas.
    81 copies = 737 draw calls.

    upload_2017-2-21_3-4-20.png


    Packed with spritepacker: 20 draw calls.

    upload_2017-2-21_3-3-7.png


    Since in this case my textures were already atlased, im wondering why we couldn't just decide what do draw when, instead of packing all in once without the possibility to load them in a selective way.
     
    Last edited: Feb 21, 2017
  49. PixelSquad

    PixelSquad

    Joined:
    Sep 4, 2014
    Posts:
    114
    Hey guys, sorry to bump this old thread.

    It seemed obvious to me that loading a sprite from the Resources folder should:
    1. Load the sprite as an independent texture when the "packing tag" is empty
    2. Load the atlas where the sprite is stored (if not already loaded) and take the sprite from it when the "packing tag" is specified
    I expected Unity to add to builds only the atlas and not the texture itself when a packing tag is specified. After going through this thread, I see many people expected the same.

    Our game will have thousands of little sprites which will be loaded depending on the state of the game, it doesn't make sense to add them to prefabs or scenes (it would be actually a huge hassle to add each sprite manually to a prefab or scene just for the purpose of it being included in a build).

    After reading this:

    It looks like the only way of doing what we need is to reference each sprite (with a scene, prefab, or scriptable object).

    The best solution in our case is to automate this by placing all the sprites we need to load this way inside a "Sprites" folder and then create a tool that scans that hierarchy and creates a mirror prefab for each sprite inside the Resources folder, and then loads that prefab instead of the sprite directly.

    I hope someone tells me I'm wrong, and that there's a better solution for this.
     
  50. Aithoneku

    Aithoneku

    Joined:
    Dec 16, 2013
    Posts:
    67
    Hi. As you can see from dates of our posts, we were never officially confirmed what's the correct solution for our shared problem and requirements. From this reason, I assume that there are only two solutions; use asset bundles and my solution with scriptable objects in Resources directory, the second one being the simplest.

    In other words, AFAIK and IMHO you're not wrong and your solution is actually best one. Please note that Unity documentations discourage using Resrouces at all, but using Asset Bundles for this purpose - AFAIK and IMHO - brings only difficulties and has not a single advantage.