在18年的UWA性能优化会议中,提到UGUI使用量开始赶超NGUI,且UGUI是官方推荐的,也逐渐成熟。因此新项目就直接上了UGUI,同时也是想弥补UGUI经验的不足,踩一些坑。在Unity2018中,Sprite图集打包除了SpritePacker,还有了官方的SpriteAtlas,在使用上其实差别不大,但是个人觉得后者更好更方便。

关于图集的作用,更多的是整合DrawCall或者说Batches。但是对于像头像图标这种量大,同屏率高的图片就比较令人头疼了。如果直接加载Texture,无法合并Batches,导致DC偏高。

那么有没有解决方案呢?在UWA会议中,小米超神分享里提到了动态图集这一方法。思考了下,不错且可行,那么我们也来一套,未雨绸缪。

首先是参考了分享中的开源地址,感觉,emmm有点不好改(也许是没什么耐心去看)。

于是开始进行思考,其实原理很简单:将许多张Texture合并到一张动态Texture中,至于排列方式类似Unity图集的形式整合就ok,然后用对应的Rect创建Sprite。完成,但是还需要有如下需求:

  1. 动态图集初始化大小。
  2. 大小能够自动拓展,且最好不用重构原有图集排列和重建Rect和Sprite对象。
  3. 动态图集有最大尺寸上限。
  4. 超过上限之后自动新建动态图集,来满足图集需求。
  5. 当然要支持管理咯!
  6. Editor下能看见动态图集全貌。

接下来我也只谈一谈大概的实现思路和关键点,并不给出代码。:-p

关于图集排列算法,使用MaxRectsBinPack。嗯,Unity Wiki里的,感觉很可靠,使用方法见代码。

需求中稍微难的是自动拓展大小,但是其实也不难,举个例子:

初始图集大小为64×64:

现在,已经放不下了,这个时候,把Texture宽高都x2,即128×128:

除了Texture需要Resize之外,对应的MaxRectsBinPack也需要Resize到128×128。

这里需要自己去实现MaxRectsBinPack的Resize方法,关键点是修改当前的尺寸,并且重新Insert原来的usedRectangles得到新的freeRectangles,用于之后的正确插入。

特别注意的点:得到的Rect坐标原点是左下角,而Texture原点是左上角(这也可以从放大后的Texture中看出),为了保证Rect、Sprite和Texture像素的对应关系需要把之前的内容移到左下角,如下图:

至此,动态图集主要功能已经基本搞定。

在使用过程中,一旦Resize后,由于UGUI只对sprite的set操作做了重建处理,所以Texture改变的时候,Image并不会立即刷新,故需要拿到当前所有Image脚本,SetVerticesDirty()其实就是强制触发一次重绘,确保显示正确。

AMAZING!

最终效果是,Batches从70~80降到50~60,效果也还是有的~

补充:后面发现内存使用会比较多,尤其在更新图集的时候,也算是一次尝试,资源管理才是王道 :D

发表评论

电子邮件地址不会被公开。 必填项已用*标注