这是之前写的一篇关于 UGUI 优化的文章,换了博客平台之后,重新再发一遍,之前的文章也翻译过官方关于 Ugui 优化的一系列文章,总结其内容,可以将 ugui 的优化归结为以下三类:
- 资源的优化
- Drawcall 的优化
- Overdraw 的优化
- Rebuild 的优化
资源的优化主要是图片的导入设置,以及图片的压缩格式选择,导入设置中重点注意两个选项:Read/Write Enable 和 Generate MipMaps,当开启 Read/Write 时,将占用两倍内存资源,关闭时将不能使用 Texture.GetPixel() 等函数来读取像素信息,如不需要请将该选项关闭,开启 Generate MipMaps 是增加 1.33被内存占用,对于 UI 资源来说,不需要开启此选项。
对于图片压缩格式,可以采用平台硬件支持的类型,Android 平台的 ETC 和 ETC2,需要注意的是前者不支持透明通道,需要分离 Alpha 通道;ETC2 是 OpenGL ES 3.0的一部分,则在某些低端机型上不支持,此时将会采用 RGBA32 格式(新版本可以通过 ETC2 Fallback 设置),另外 Android 平台默认采用 RGB(A) Compressed ETC2 格式。IOS 平台可选的有 ASTC 和 PVRTC,ASTC 的效果比较差,但是性能最好,如果美术可以接受的话,可以考虑使用,平台默认采用 RGB(A) Compressed PVRTC 2/4 Bits 格式。
Drawcall 的优化其实主要是图集打包策略的选择,以及合批处理,关于哪些情况会中断合批,前面的文章也详细地做了介绍,同时,Unity 的 Profiler 当前提供了 UI 模块,能够很清楚的知道哪个对象引起合批中断,中断原因,帮助我们很好的进行界面调优。
Rebuild 通常可能是 UGUI 优化的重灾区,每一次 Rebuild 都需要重新的生成合批的网格,造成 Rebuild 的原因有很多,之前的文章也介绍过,Rebuild 优化宗旨是,尽可能减少 Rebuild 次数,尽可能减少 Rebuild 影响范围,主要实施方案是:
- 采用动静分离,对于动态 ui 元素,使用单独的 Canvas 进行渲染,
- 最好采用 TMP 文字来替代 UGUI 的文字渲染,
造成 Overdraw 的原因前文也介绍过,因为 UGUI 生成的网格都是矩形,而 UI 的渲染是在半透明队列,所以多层 ui 的叠加是造成 overdraw 的主要原因,针对 Overdraw 的优化,主要总结三点:
- 避免全透明 Image,有些时候为了接收 UI 某个事件而使用全透明 Image,虽然其不可见,但是仍然会进行一遍渲染;
- 对于 Sliced 类型,如果只需要渲染边框,避免勾选 FillCenter 选项(将不会生成中间部分网格);
- 对于不规则图片,可以采用本文介绍的多边形组件;
下面详细介绍多边形组件的实现方式,以下是之前原文:
在使用UGUI Image组件显示不规则图片、镂空图片时,Image总是会创建一个四边形网格来显示图形,渲染过程中,GPU需要对完全透明的区域进行计算,这不利于性能的优化,一个解决办法是采用多边形网格显示图形,来减少这种不必要的消耗。
下面是Image组件和多边形显示组件的网格对比
下面是Image和多边形的Overdraw对比
整个方案的实现过程包括以下几个步骤:
- 生成图集,这里推荐使用 Texture Packer,这里要求导出 tpsheet 格式。
- 导入图集、生成多边形,这里需要从AssetStore下载TexturePackerImporter(已经包含的项目中)。到导入插件之后,将 tpsheet 文件和图集一起导入项目中,导入之后TexturePackerImporter会自动将图集转换成带多边形的Sprite。
- 使用UIPolyImage组件替换 Image 组件。(该组件目前只支持 Simple 模式)
如果需要根据图形做射线检测,在 UIPolyImage/Image 组件上添加PolyRaycastFilter 组件。因为该组件需要读取贴图的像素,所以需要将贴图的 readAndWrite 属性勾选。
示例项目:这里
多边形Image组件
1 | using System.Collections; |
射线检测过滤组件
这里实现方式是通过获取像素的 Alpha 值来进行判断的,所以一个明显的缺点就是需要将贴图的 Read/Write 设置为true,造成图片资源内存占用翻倍。当然还有一些其他的方法也可以实现功能,比如设置多边形碰撞、多边形检测等等,后续如果有机会的话,会补充其他的方法。
1 | using System; |
基于多边形检测
判断某点是否在多边形内,通常采用的方法有交点法、回转数法,本文采用的是交点法来计算,具体原理网上有更详细的文章来介绍,这里直接上代码,工程源码里对应PolyMeshRaycastFilter.cs
文件。
1 | using System; |
基于 PolygonCollider2D 检测
这种方法是采用 Unity 的 2D 多边形碰撞体 PolygonCollider2D,其提供了相应的检测方法,对应工程的 PolyColliderRaycastFilter.cs
文件,代码如下:
1 | using System; |
总结
本文主要介绍了优化 Overdraw 的一种方法,如果在项目中遇上 Overdraw 严重的情况,可以考虑采用这种方法,后续有时间再介绍 ugui 的其他优化内容。