上周挂掉腾讯三面的时候被点去好好看看UGUI优化部分的东西,咱一直很听劝,就拿着以前用UGUI做的游戏研究了一下。
不看不知道,以前做的UI真是把坑踩完了,一个卡牌仓库连60帧都稳不住,真是让人流汗…
下面是优化的完整思路(注:仅针对于减少batches)

优化前




这是一个明日方舟同人游戏的卡牌仓库界面,所有卡牌都绘制在一个横向的ScrollView上。我曾将相关纹理打包图集,但并没有做任何其他的优化处理
进行此次优化前,场景绘制的总批次为879,每张卡片占用11Batches,没有发生任何的合批。编辑器运行无法稳定在60FPS。

优化流程

  1. 将所有可以替换的RawImage替换为Image。这是因为即便使用同一图集的不同纹理,多个RawImage也不会进行合批
    • 总批次879 -> 737
    • 每张卡牌独占10个Batches(每张卡的2个Image进行了合批)

  2. 将所有Sprite为空的图像填充上同图集中全白的图像。这是因为即便材质相同,空Sprite图像和有Sprite的图像也不能合批(视作非同图集的纹理)。
    • 总批次717 -> 474
    • 每张卡牌独占6个Batches
  3. 用CanvasGroup来管理“未解锁”和解锁卡牌的UI元素。因为即便是被遮挡的元素也会被渲染,造成性能损耗,而通过CanvasGroup设置为透明的元素则不会被渲染。(只要没有勾掉默认开启的Cull Transparent Mesh)
    • 总批次474 -> 210
    • 每张卡牌独占2/4个Batches
  4. PosZ置零+移除Rect Mask 2D
    1. 当UGUI元素的z轴不为0时或者旋转角不为90的整数倍时,分批的Bounds检测失效。即视为所有组件重叠在一起,渲染顺序严格按照Hierarchy顺序。该项目设计时单纯靠将加载进来的卡牌的父物体设定为带有Layout组件的物体PosZ不为零,无法合批。故添加一行代码,加载物件时将PosZ置零。
    2. Mask内的元素可以合批,但是Mask内外的元素不可以。对每一张卡牌都用Mask遮罩导致不同卡牌之间无法合批,应该去除组件。(我在此处找到了不打断合批的Mask解决方案)
    • 总批次210 -> 23
    • 卡牌不再独占Batch
    • FPS基本稳定在200以上
  5. 对象池动态加载对象。原方案是一次性加载所有卡牌,没有看到的卡牌就直接挂在画面之外。如果只是想减轻渲染压力的话,将画面外的整张卡牌都用CanvasGroup隐藏就行了,但是追求更好性能的话还是要用对象池。(暂未实现)

相关资料

不打断合批的Mask解决方案