使用契机:
目前在做的是一个Merge类型的休闲游戏,就是类似于三消棋盘那种一格一格的,每个格子都可能会有不同的元素图案,类似比较典型的游戏《绯闻港口》
类似这种,每个格子里都是一张小图,而这些个小图的种类,根据游戏设定可以有好几百个,我们游戏目前是已经有了500+种东西,任意一种都可能出现在棋盘的某一个格子里。
那么问题来了,这些小图要不要打成传统图集呢?
不打: 那就不能进行渲染合批,理论上79的格子阵,就光绘制格子里东西就要至少63个drawcall,且每一个小drawcall就只绘制一张那么小的图,怎么想都不划算。
打: 问题在于小图的数量太多了,有500+,每个小图102102像素大小,打成1024大小的图集要打5张,这样即使可以让小图合批渲染,但是每次不管使用几张图,哪怕是只用了1张小图,也要加载出整个5张1024的大图集,也很亏,而且这么大的一张图集在一些带宽较差的手机上也吃不消。
所以经过大佬指点,就采取了 动态图集 方案:通俗的说,就是运行时再确认图集,运行时将当前场景上的小图”复制“到一张大图上,渲染时用这张大图来渲染,当场景内元素变化时,也根据策略变化这个大图,比如出现了一张新的图,原来图集里没有的,那就把他添加复制上去,反之可以减少下去,(这个根据策略调整,我这个项目就只加不减,当图集装不下了再清空重新生成)
代码
这么牛逼的东西我这种菜鸡是弄不出来的,肯定是从网上找现成的,上链接!
https://github.com/tkonexhh/DynamicAtlas 用的是这个github上大佬的demo,他说的也很清楚
使用方法也很简单,直接下载他这个demo到工程里,在你想要放在动态图集里的Image替换成他的组件DynamicImage,然后group选择成一样的,就会自动打成动态图集了,这里不在赘述。以下提几点个人心得以及注意的地方:
1.关于卸载: 当你切换到别的场景完全不用这个动态图集的时候,肯定是要卸载掉它的。具体方法除了他demo已经写好的几个卸载字典数据的方法ClearAllCache之外还要记得卸载每个DynamicAtlasPage类里的m_Texture对象,这个就是动态图集本身了,直接用 GameObject.Destroy(m_Texture); m_Texture = null;
卸载就好了,另外还有一个就是绘制图集时候产生的Color变量private Color32[] m_TempColor;
这个数组也是个容量很大的东西,不卸载的话在一些非常差的手机上也会产生影响。像我就直接这样卸载了:
public void Clear()
{
foreach (var data in m_UsingTexture)
{
DynamicAtlasMgr.S.ReleaseSaveTextureData(data.Value);
}
m_UsingTexture.Clear();
foreach(var kv in m_PageList)
{
kv.ReleaseAtlas();
}
m_PageList.Clear();
m_TempColor = null;
}
2.关于有些设备不支持:我在写完了动态图集的代码之后兴冲冲的找测试开始测试,结果测试同学一装上包,一打开看,啥呀?一片空空如也。 我蒙了,这是为啥,我拿过他的测试机,查看了一下log,没有报错。在我自己手机上和电脑上都运行的好好的,这是怎么回事?好奇怪呀! 这时候我灵光一闪,之前下载完代码的时候大概看了一遍看到了一个眼生的函数
public void AddTexture(int posX, int posY, Texture2D srcTex)
{
Graphics.CopyTexture(srcTex, 0, 0, 0, 0, srcTex.width, srcTex.height, m_Texture, 0, 0, posX, posY);
}
这个copyTexture函数我之间没见过,就上网搜了下API,原来就是字面意思,是把你的小图拷贝到大图(图集)上的一个函数,相比用for循环一个一个 getPixel和SetPixel拷贝,这个函数会更加高效。而且我记得我看这个函数api介绍的时候那个地方写着有些设备不支持,会不会就是因为这个?我就又去查看了一下
果然,我打印了一下测试机的support信息发现是不支持,而我的手机是支持的。原来如此,幸亏我之前多看了一眼这个代码,不然就不知道要猜测原因猜多久。于是我写了个宏判断,不支持这个copy函数的设备就不用动态图集,多点drawcall就多点吧,因为我尝试用getpixel逐像素点拷贝那个性能开销太恐怖了。。。所以跟我一样做面向海外项目的同学要注意下这点了,他们的设备指不定有多差。。也许就各种不支持。。。要做好相应的对策哦~
3.这个属于题外话了,跟动态图集没关系了。我换成动态图集加载小图之后,测试和领导纷纷反应这个游戏运行比原来慢的多了,总是卡卡的。我原来是以为生成动态图集的时候卡,后来经过对比实验,我就是不打动态图集,只是加载小图也卡。那是因为啥呢,此时我忽然想到一个思路,我们是用addressable bundle进行的资源管理,我们这500+小图目前是放在一个bundle里的,会不会是因为这个bundle里这个文件数量太多,所以每次从bundle里索引内容的时候非常缓慢呢?立刻开始试验,我把bundle里图删去一半,再打包运行,明显没有原来卡了!我这神一般的直觉哈哈哈哈(可把我牛逼坏了)!可能bundle里的的加载方式对文件数量很大的时候不太友好吧。于是果断采取策略,分几十个bundle装,然后每个小图配路径,这样加载起来就不卡啦!
其实中间淌了不少坑,想起来就记录一下,希望能帮到大家一点~
至于动态图集里面空间,位置具体是怎么计算的,好像挺复杂的,有时间再研究研究哈哈哈哈~