• Runtimes
  • How to Store Skins in Unity

Hi everyone,

I'm planning to create a skeleton with a very large number of skins (possibly thousands or more) to use for customized characters. I might generate a large number of random NPCs or enemies (over 100) in a short period of time using these skins. To optimize performance, I plan to group the skins and store them in ScriptableObject assets to use them when needed. However, since skins cannot be serialized, I'm not sure if they can be stored this way. If I only store the skin.name as strings, it seems that each time I'd still need to use findSkin to search through thousands of skins, which wouldn't optimize the search speed.

Is there a way to store a list of skins in a ScriptableObject, or is there a better solution to optimize the performance of quickly matching a large number of skins to a large number of NPCs? Thank you very much! 🙂

Related Discussions
...

Storing a large number of skins in Unity and optimizing their performance can be challenging, but there are several strategies you can employ to manage and optimize the process:

  1. Group Skins by Archetypes: As suggested in the context, you can group skins by archetypes or common features and separate them into different files. This helps in managing and loading only the necessary skins, reducing memory usage and improving performance.

  2. Use ScriptableObjects for Metadata: While you cannot directly serialize skins, you can use ScriptableObjects to store metadata about the skins, such as their names, categories, and any other relevant information. This allows you to quickly access the necessary data without having to search through all skins.

  3. On-Demand Loading: Implement on-demand loading and unloading of skins. This can be done by creating a SkinLoader component that handles the loading of skins only when they are needed. This approach ensures that only the required skins are loaded into memory, reducing the overall memory footprint.

  4. Runtime Skin Creation: Consider creating skins at runtime and populating them with attachments as needed. This can save a lot of effort and memory when dealing with a large number of skins. You can use an AttachmentLoader to control which textures are loaded based on the attachments that are actually visible.

  5. Repacking Skins: Use runtime repacking of skins to combine multiple skins into a single atlas. This can help in reducing draw calls and improving rendering performance. The GetRepackedSkin or GetRepackedAttachments methods can be used for this purpose.

  6. Efficient Skin Lookup: Instead of using SkeletonData.FindSkin() to search through thousands of skins, you can create a dictionary that maps skin names to their corresponding skin objects. This allows for O(1) lookup time, significantly improving the search speed.

Here is an example of how you might implement a SkinLoader component in Unity:

public class SkinLoader : MonoBehaviour
{
    private Dictionary<string, Skin> skinDictionary = new Dictionary<string, Skin>();

    public void Initialize(SkeletonData skeletonData)
    {
        foreach (var skin in skeletonData.Skins)
        {
            skinDictionary[skin.Name] = skin;
        }
    }

    public Skin GetSkin(string skinName)
    {
        if (skinDictionary.TryGetValue(skinName, out Skin skin))
        {
            return skin;
        }
        else
        {
            Debug.LogWarning($"Skin {skinName} not found!");
            return null;
        }
    }
}

In this example, the SkinLoader component initializes a dictionary with all available skins, allowing for quick lookup by skin name.

By combining these strategies, you can effectively manage and optimize the performance of a large number of skins in Unity.