Unity打包图集
目前用到了两种图集打包的方式:sprite packer and sprite altas
Sprite Packer
流程:
- 打开 Edit -> Project Setting -> Editor
- 选择Always Enabled(Legacy Sprite Packer)模式
- 单独给每个需要打包的图片设置type和mesh
- 只有设置了tag值才会进行打包,相同的tag值打包到同一个图集,不同的Tag值打包为不同的图集
- 下面的mesh type:
- Tight: 是紧密打包方式,也就是尽可能的把图片都打包在图集上,更省空间
- Full Rect:会把所有的小图按照矩形的方式来排列,如果宽高不一样的图片,它们会自动补起
-
打开 Window --> 2D --> Sprite Packer 点击左上角的 pack 就可以啦
注意:放在Resources文件夹中的图片,Unity不会打包到图集中;打包好的图集会放在缓存文件夹Project\Library\AtlasCache里面
Sprite Altas
2017以后的版本,我们项目目前用的也是这种
流程:
- 打开 Edit -> Project Setting -> Editor
- 选择Always Enabled模式
- Project框里右键-> create -> sprite atlas
- 可以将文件夹,纹理或精灵分配给Sprite Atlas。可以将整个文件夹分配给Sprite Atlas资产,该文件夹中的所有纹理(包括子文件夹)都将被打包
- 打包的结果可以实时的在窗口里看到
Atlas还有一个类型是Variant
Variant它会复制原图集的贴图,并根据一个比例系数来调整复制贴图的大小。通常用于为高分辨率和低分辨率的屏幕准备不同的图集,高级设备用高分辨率,低级设备用低分辨率
scale改成0.1后,可以看到上面第一个明显模糊很多
相比sprite packer的优点
- 实时查看图集的大小
- 实时查看图集里面元素的排列布局
- 增加了LateBinding(不勾选include in build)等特性。一旦启用Late Binding,Unity把Prefab和Atlas的依赖关系是会解开,毕竟在以前,依赖的资源必须在Prefab加载或实例化之前准备好才行,但Late Binding是不需要
图集访问
Sprite Atlas作为一种资源开放给用户,可以在脚本中访问,还可以通过名字获取图集中的精灵。这样用户可以更加直接地随时编辑图集,而且不用去单独加载图集中的每个精灵
var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(a.AssetPath); if (atlas == null) continue; var s = atlas.GetSprite(spriteName); if (s != null) { GetComponent<SpriteRenderer>.sprite = s; }
注意:
- UGUI的图集,无论新旧,在构建AssetBundle的时候,同一个图集内的所有图元都要放在同一个AssetBundle中,否则,如果同一个图集的图元被分散到多个AssetBundle中,那么每一个AssetBundle都会包含一份这个图集的Copy,最终的结果就是包体冗余、内存膨胀和加载耗时等问题。
- SpriteAltas文件可勾选Include In Build,但是不要特意打包,会造成冗余和包体膨胀
- 代码中动态加载Sprite的地方,直接使用散图的资源路径去加载就可以了,比如:var sprite = Assets.LoadAsset<Sprite>(path);
为什么图集可以减少drawcall
官方文档有提到
图集它是一种将多个纹理合并为一个组合纹理的资源。Unity 可以调用此单个纹理来发出单个绘制调用而不是发出多个绘制调用,能够以较小的性能开销一次性访问压缩的纹理
简单点说就是:使用图集,我们就可以归类不同种类的图片,之后就可以一次进行多张图片的绘制处理,只需调用一次DC,提高了效率。
我们再来深挖一下drawcall, 到底什么是drawcall?
Draw Call就是一个命令(也是CPU调用图形编程接口,比如DirectX或OpenGL),一个由CPU发起,命令GPU执行的命令,就是CPU告诉GPU可以对某个模型进行渲染处理的传话人。一般来说一个独立的模型会产生一个Draw Call,但是如果经过一些特殊的处理,比如所动态合批,静态合批等等操作,就会降低Draw Call。
那么为什么drawcall会影响CPU性能呢?
CPU将Draw Call发往GPU过程中并不是很直接的就交给GPU,而是先将这些数据存到一个命令缓冲区内,然后再后面的几何阶段由GPU进行数据的读取。GPU的渲染能力是很强的,渲染300个和3000个三角网格通常没有什么区别,因此渲染速度往往快于CPU提交命令的速度。Draw Call的数量太多,CPU就会把大量时间花费在提交Draw Call命令上,造成CPU的过载
为什么图片的大小要设成2的N次方
因为大部分游戏引擎底层的渲染方式都是基于OpenGL的,OpenGL载入纹理图片时,所用内存会自动扩张到2的N次方(500 x 500 → 512 x 512)。
- 因为转化过程比较慢,由运行程序转换十分耗时,所以Unity3D提前将资源转化为符合标准的图片,这样可以提升转化速度
- 节省内存。一张图片的大小为10*10像素,OpenGL会按照16*16的规格将图片载入到内存中;如果图片大小为64*65,那么就会按照64*128载入了,这就造成了内存的无必要开销。
- 减少包体。打成图集后的合成的大图会比之前所有的散图所占用的物理存储更小。这样从通过减小图片资源物理存储大小起到压缩游戏安装包的作用。
Reference:
- https://blog.csdn.net/weixin_36961960/article/details/86707085
- https://zhuanlan.zhihu.com/p/391885850
- https://zhuanlan.zhihu.com/p/89332754