Unity性能优化 - 动态图集

一、什么是动态图集:

Unity 动态图集是 Unity 引擎中用于处理游戏纹理优化的一种技术。它可以将多个纹理打包到一个图集中,减少游戏中需要加载的纹理数量,从而提高游戏性能。

在运行时,Unity 动态图集会根据游戏需要动态地生成纹理,并将它们打包到一个图集中,这样可以大幅降低游戏加载时间和内存占用。

二、动态图集的优缺点:

 Unity 动态图集的优点包括:

  1. 减少纹理加载时间:使用动态图集可以将多个纹理打包成一个图集,在运行时只需要加载一个纹理,从而减少加载时间和内存占用。
  2. 提高游戏性能:减少纹理加载时间和内存占用可以提高游戏性能,并使游戏在不同平台上更加稳定。
  3. 简化开发过程:Unity 动态图集可以自动管理纹理的打包和加载,简化了开发过程,减少了手动操作的需要。

 Unity 动态图集的缺点包括:

  1. 生成图集需要一定的计算资源:在生成动态图集时需要一定的计算资源,如果游戏中的纹理较多,可能会导致游戏卡顿或者运行缓慢。
  2. 需要调整纹理尺寸:在使用动态图集时,需要将不同尺寸的纹理进行调整,否则可能会导致纹理失真或者变形。
  3. 需要一定的配置和调试:使用动态图集需要一定的配置和调试,需要对游戏的纹理进行分类和打包,以便在运行时生成动态图集。

三、动态图集的实现方案:

本文不过多阐述关于动态图集的原理,直接上一个简单的demo来让大家来理解动态图集。

下面是动态图集的管理类:

using System.Collections.Generic;
using UnityEngine;

public class DynamicAtlasManager : MonoBehaviour
{
    public int atlasSize = 2048;
    public TextureFormat textureFormat = TextureFormat.RGBA32;
    public bool useMipmaps = false;

    private static DynamicAtlasManager _instance;
    public static DynamicAtlasManager Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject("DynamicAtlasManager");
                _instance = go.AddComponent<DynamicAtlasManager>();
            }

            return _instance;
        }
    }

    private Dictionary<string, Texture2D> _atlasDictionary;
    private Dictionary<string, Rect> _spriteRects;
    private Dictionary<string, Sprite> _originalSpritesCache;

    void Awake()
    {
        _atlasDictionary = new Dictionary<string, Texture2D>();
        _spriteRects = new Dictionary<string, Rect>();
        _originalSpritesCache = new Dictionary<string, Sprite>();
    }

    public void AddSpritesToDynamicAtlas(string atlasName, Sprite[] sprites)
    {
        if (sprites == null || sprites.Length == 0) return;

        Texture2D atlas;
        if (_atlasDictionary.ContainsKey(atlasName))
        {
            atlas = _atlasDictionary[atlasName];
        }
        else
        {
            atlas = new Texture2D(atlasSize, atlasSize, textureFormat, useMipmaps);
            atlas.filterMode = FilterMode.Bilinear;
            _atlasDictionary.Add(atlasName, atlas);
        }

        for (int i = 0; i < sprites.Length; i++)
        {
            if (!_originalSpritesCache.ContainsKey(sprites[i].name))
            {
                _originalSpritesCache.Add(sprites[i].name, sprites[i]);
            }
        }

        int xOffset = 0;
        int yOffset = 0;
        int maxHeight = 0;

        for (int i = 0; i < sprites.Length; i++)
        {
            Sprite sprite = sprites[i];
            Texture2D spriteTexture = sprite.texture;

            if (xOffset + sprite.rect.width > atlas.width)
            {
                xOffset = 0;
                yOffset += maxHeight;
                maxHeight = 0;
            }

            // Copy the texture using CopyTexture method
            Graphics.CopyTexture(spriteTexture, 0, 0, (int)sprite.rect.x, (int)sprite.rect.y, (int)sprite.rect.width, (int)sprite.rect.height, atlas, 0, 0, xOffset, yOffset);

            _spriteRects[sprite.name] = new Rect(xOffset, yOffset, sprite.rect.width, sprite.rect.height);

            xOffset += (int)sprite.rect.width;
            maxHeight = Mathf.Max(maxHeight, (int)sprite.rect.height);
        }
    }


    public Sprite GetSpriteFromDynamicAtlas(string atlasName, string spriteName)
    {
        if (!_atlasDictionary.ContainsKey(atlasName) || !_spriteRects.ContainsKey(spriteName))
        {
            return null;
        }

        Texture2D atlas = _atlasDictionary[atlasName];
        Rect spriteRect = _spriteRects[spriteName];

        // Get the original sprite
        if (!_originalSpritesCache.ContainsKey(spriteName))
        {
            return null;
        }

        Sprite originalSprite = _originalSpritesCache[spriteName];

        // Calculate the border of the new sprite based on the original sprite's border
        Vector4 border = originalSprite.border;

        // Create the new sprite with the correct border
        return Sprite.Create(atlas, spriteRect, new Vector2(0.5f, 0.5f), originalSprite.pixelsPerUnit, 0, SpriteMeshType.Tight, border);
    }
}

 下面是动态图集的demo代码:

using UnityEngine;
using UnityEngine.UI;

public class DynamicAtlasDemo : MonoBehaviour
{
    public Sprite sprite1;
    public Sprite sprite2;
    public Sprite sprite3;
    public Image image1;
    public Image image2;
    public Image image3;

    private DynamicAtlasManager _dynamicAtlasManager;

    void Start()
    {
        _dynamicAtlasManager = DynamicAtlasManager.Instance;

        // Add sprites to the dynamic atlas
        _dynamicAtlasManager.AddSpritesToDynamicAtlas("DemoAtlas", new Sprite[] { sprite1, sprite2, sprite3 });

        image1.sprite = _dynamicAtlasManager.GetSpriteFromDynamicAtlas("DemoAtlas", sprite1.name);
        image2.sprite = _dynamicAtlasManager.GetSpriteFromDynamicAtlas("DemoAtlas", sprite2.name);
        image3.sprite = _dynamicAtlasManager.GetSpriteFromDynamicAtlas("DemoAtlas", sprite3.name);
    }
}

优化前的draw call数量:5

优化后的draw call数量:3

 

扫描二维码关注公众号,回复: 14907552 查看本文章

备注:

上面的动态图集只是一个简单的方案,可以根据项目需求进行扩展和优化。

欢迎大家点赞评论关注三连,性能优化持续更新中。

猜你喜欢

转载自blog.csdn.net/qq_33808037/article/details/130018125