在 Unity 中,动态图集(Dynamic Atlas)是一种在运行时将多个纹理合并成一个大纹理图集的技术,这样可以减少渲染时的纹理切换次数,提高渲染效率。
实现原理:
动态图集的核心思想是在运行时动态地将多个小纹理合并到一个大的纹理中,形成一个纹理图集。
主要步骤如下:
创建一个大的空白纹理:作为最终的纹理图集。
纹理分配:使用合适的算法将小纹理放置在大纹理的空闲区域。
复制纹理数据:将小纹理的数据复制到大纹理的相应位置。
更新材质和 UV 映射:使用新的纹理图集更新材质,并调整 UV 映射以正确显示小纹理。
定义图集的基础属性:
// 图集的宽度
public int atlasWidth = 1024;
// 图集的高度
public int atlasHeight = 1024;
// 要合并的纹理列表
public List<Texture2D> texturesToMerge;
// 最终生成的图集纹理
private Texture2D atlasTexture;
// 每个纹理在图集中的位置和大小信息
private List<Rect> textureRects;
然后导入几张图片
并且图片的Read/Write属性要打开,
否则会报如下错:
然后创建一个Texture2D
atlasTexture = new Texture2D(atlasWidth, atlasHeight, TextureFormat.RGBA32, false);
使用 Texture2D中的PackTextures方法(其中纹理匹配算法使用的是Unity内置的矩形装箱算法),将多个纹理打包到一个纹理图集中:
textureRects = new List<Rect>(atlasTexture.PackTextures(texturesToMerge.ToArray(), 2, atlasWidth));
结果:使用RawImage显示合并后的图集
纹理分配算法:
1. 四叉树算法(Quadtree Algorithm)
原理:
将大纹理(容器)看作一个根节点,不断将其递归地分割成四个子节点(四叉),直到每个子节点要么完全被一个纹理占据,要么太小无法再放置纹理。
放置纹理时,从根节点开始检查,如果当前节点能容纳该纹理,则尝试将其放入该节点;如果不能,则递归地检查其子节点。
优点:
适合处理动态变化的纹理集合,插入和删除纹理相对方便。
可以较好地处理不同尺寸的纹理。
缺点:
实现相对复杂,需要维护四叉树的数据结构。
可能会产生较多的小空闲区域,导致空间利用率不高。
2. 遗传算法(Genetic Algorithm)
原理:
把矩形的放置方案看作一个染色体,每个染色体包含多个基因(每个基因代表一个矩形的放置位置)。
初始化一个包含多个染色体的种群,通过选择、交叉和变异等遗传操作不断进化种群,直到找到最优或近似最优的放置方案。
优点:
理论上可以找到全局最优解或接近全局最优解。
可以处理复杂的约束条件。
缺点:
计算复杂度高,需要较长的计算时间。
参数调整比较困难,不同的参数设置可能会导致不同的结果。
3.矩形装箱算法:
优点:
简单易懂,实现相对容易。
能在一定程度上减少空间浪费,提高容器的利用率。
缺点:
可能无法得到最优解,尤其是对于复杂的矩形组合。
时间复杂度较高,对于大量矩形的情况,性能可能会受到影响。
具体实现:
相关实现链接:
Unite 2016 - Building Sprite Sheets at Runtime (Top Eleven, Nordeus) - YouTube
DynamicSpriteSheets/DynamicAtlasses/TexturePacker.cs at master · dusanst/DynamicSpriteSheets (github.com)
tkonexhh/DynamicAtlas (github.com)
DaVikingCode/UnityRuntimeSpriteSheetsGenerator: Unity – generate SpriteSheets at runtime! (github.com)