Unity编辑器扩展: 程序化打图集工具

请添加图片描述

开始前的声明:该案例中图集所使用图片资源均来源于网络,仅限于学习使用

一、前言

关于编辑器扩展相关的知识,在前面的两篇内容中做了详细的描述,链接地址:

第一篇 :Unity编辑器扩展 UI控件篇

第二篇 :Unity编辑扩展:功能篇之Json数据编辑器

前两篇着重于介绍编辑器界面扩展相关控件接口的使用方式。作为系列文章的第三篇,会更偏重于引擎内编辑器扩展承担 的提升开发效率的功能模块设计

通过程序化打图集减少工作量的同时可以稳定全局的管理图集,避免随着项目膨胀手动管理产生资源上的混乱。从图集整个生命周期来说,对于图集管理通常需要下面的模块支持:

  • 程序化图集打包
  • UI界面引用图集检测工具
  • 图集资源自动/手动加载、卸载框架支持

本篇文章介绍第一部分,即图集程序化打包的逻辑执行

1、关于图集

官方文档对精灵图集的描述:

2D 项目使用精灵和其他图形来创建其场景的视觉效果。这意味着单个项目可能包含许多纹理文件。Unity 通常会为场景中的每个纹理发出一个绘制调用。但是,在具有许多纹理的项目中,多个绘制调用会占用大量资源,并会对项目的性能产生负面影响

精灵图集 (Sprite Atlas) 是一种将多个纹理合并为一个组合纹理的资源。Unity 可以调用此单个纹理来发出单个绘制调用而不是发出多个绘制调用,能够以较小的性能开销一次性访问压缩的纹理。此外,精灵图集 API 还可以控制如何在项目运行时加载精灵图集

图集对性能开销的正向影响:

从文档描述中可以看出,图集主要在两方面影响影响性能开销:

第一,减少绘制调用,即提升合批数量,减少Draw Call

从文档的描述可以看出,图集概念出现与渲染的绘制调用相关,衡量绘制调用通常以Draw Call数量为标准。而在Unity中UI合批策略,不同的Image控件要执行合批必须要有相同的材质、Texture。为了满足该条件,将一些小图合并成为大图片,就可以在渲染时,尽可能的一次性的将渲染数据提交给GPU

第二,合理的图集打包策略利于资源的压缩

在前面的性能优化文章中有提到过,某些压缩策略通常只会对规则大小的图片资源生效。如下图提示,当导入的图片资源非2倍数时,引擎会弹出对应警告信息。Unity引擎对Texture资源的常用的DXT压缩处理需要满足其宽度与高度的必须为4的倍数(这是因为DXT压缩策略是以4X4的像素块为基本单位做处理)
在这里插入图片描述

而对于图集而言,其尺寸设定策略时基于是以2的次方为基本数值,即图集是可以执行压缩的。而资源的压缩无疑会提升资源的载入速度

图集对性能开销的负面影响:

如果图集使用不当,也可能会额外占用大量的内存,举例来说,如果当前界面只使用了某一图集中很小的一张图片,却不得已将整张图集加载到内存中。亦或者说由于打入图集的Sprite的尺寸不合理,使得图集产生大量的空白,产生额外的性能消耗

2、Unity中图集打包方法

在Unity中手动打出图集的方法,在之前的文章有描述,这里稍微做一些描述,如果想了解详细的操作过程,可以查看该文章,链接地址:

Unity 将Sprite打包进图集

Sprite Packer:

2020.1或更早的版本中,Unity提供了Sprite Packer图集纹理的生成和使用方法。相比于其他的打图集方式,Sprite Packer是封装性较高的方式。通常只会对相应的Sprite预设好指定图集标签。后续图集本身的资源管理基本由引擎自设定。这样做的优势可以减少开发者的工作量,但同时也牺牲了开发者对资源管理的灵活性。而不同项目的资源利用策略的不同又很需要这样的灵活性来定制

Sprite Atlas:

通过Sprite Atlas打出图集会生成对应的序列化配置文件,并且在资源面板是可见与可编辑的,可以灵活的控制图集资源的载入与卸载,当然也可以默认使用Unity自设定的加载与删除策略

动态图集:

动态图集是相对比较高阶的打图集解决方案,由于Unity没有提供与之对应的处理方法,意味着要自己实现一套集合动态资源管理、高效的图集生成算法等等

抛弃实现难度,动态图集目前是对于某些动态UI元素(如王者荣耀英雄头像)界面少有的解决方案

二、代码结构

在对图集的理论知识做完解释后,开启核心的程序设计阶段。后面的内容主要集中于对图集程序化过程的代码解释,主要是路径围绕编辑器内资源的遍历查询、创建删除与对图集打出参数操作方面的功能模块做设计

1、数据结构设计:

该图集生成工具的编辑器的界面操作逻辑不是很复杂,不过也需要维护一个简单的数据类。来记录编辑的缓存数据

除了一些常规的标识ID字段与简单的资源索引字段。稍微需要注意的是,在于对本地文件索引后SpriteAtlas的对象的直接保存在某些操作后造成索引丢失而出现空引用。所以这里的atlas字段会指向本地资源的实例话数据的缓存,来避免指向丢失,影响后续的数据操作

public class AtlasData
{
   
    public string atlasName;
    public string assetPath;
    /// <summary>
    /// 缓存中的SpriteAtlas,不直接指向本地资源
    /// </summary>
    public SpriteAtlas atlas;
    public List<Sprite> sprites;

    //编辑器界面数据
    public bool isShowDital;
}

2、获取某文件夹下的所有符合图集生成规范的Sprite类型的资源:

通过遍历该文件夹下所有文件(不包括子文件下的文件),并筛选出满足条件的Sprite文件,得到该路径文件夹下的Sprite列表。

这部分代码的逻辑设计集中于资源路径的读取遍历,基于DirectoryInfo得到所有的文件信息,得到文件路径并通过AssetDataBase来加载特定的Sprite类型文件资源

在对特定类型资源文件执行遍历时,可以优先排除数量较大的Meta文件,减少查询数量,提升文件遍历的操作效率。Unity中文件类型通常有资源文件、代码文件、文本文件、序列化文件、Meta文件等,通常来说,所有在UnityAsset面板中可见的文件资源都会对应一份同名的meta文件,用来记录类似于GUID等标识身份相关的信息或者与对应资源相关的设定数据

	List<Sprite> GetFileSprites(string relativePath)
    {
   
        if (Directory.Exists(relativePath))
        {
   
            DirectoryInfo direction = new DirectoryInfo(relativePath);
            FileInfo[] files = direction.GetFiles("*");//只查找本文件夹下
            if (files == null) return null;
            
            List<Sprite> sprites = new List<Sprite>();
            foreach (var file in files)
            {
   
                if(file.Name.EndsWith(".meta")) continue;
                var item = AssetDatabase.LoadAssetAtPath<Sprite>(relativePath + file
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心之凌儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值