Unity 特效性能分析工具
文章目录
介绍
Unity 中的特效在制作过程中往往会只注重效果,而忽视性能。往往做了很多特效之后才发现真机上同时播放多个特效时卡顿。
特效与其他原始资源(模型、纹理、动画等等)不同,前者是动态的,而后者是静态的。因此不能使用传统的分析方法只看一些静态的数据是否正确,而必须记录动态的数据。
搜索了一下,发现有人已经写好了一个工具:sunbrando/ParticleEffectProfiler: Unity 特效性能分析工具
看简介发现支持的功能很多:贴图内存占用、DrawCall 数量、粒子数量、特效原填充像素点、特效实际填充像素点、OverDraw 比率等等。
环境
- Unity 5.6.6f2
需求
由于文档中并未对功能进行详细的说明,因此需要阅读源码确认:
- 确定所有功能含义以及获取的数值是否正确,如有错误需修正。
- 修正在检查过程中发现的问题。
- 补充缺失功能,如显示贴图数量、ParticleSystem 数量等等。
- Unity 版本兼容问题。
- 整合进项目后,打包时会报错UnityEditor找不到 · Issue #1 · sunbrando/ParticleEffectProfiler。
问题
兼容问题
ProjectSettings/ProjectVersion.txt
显示的版本号是 Unity 2017.2.2f1,因此在目标版本 Unity 5.6.6f2 上有一些 API 不存在,需要手动加入版本宏定义进行处理。
例如粒子数量是通过反射调用 Unity 2017.2.2f1 中的 ParticleSystem.CalculateEffectUIData
,需要修改为 Unity 5.6.6f2 的 ParticleSystem.CountSubEmitterParticles
。
获取信息不正确
检查源代码发现获取贴图内存使用的是 Profiler.GetRuntimeMemorySizeLong
API,在编辑器下显示的是编辑器所在的平台内存占用,而不是目标平台的内存占用。
因此修改为通过反射调用的 Unity 私有 API UnityEditor.TextureUtil.GetStorageMemorySize
,这是预览窗口中显示目标平台内存大小的 API。
DrawCall 数值为什么比实际大 2 倍?
在 Stats
视图中显示的 DrawCall 数值,使用工具时的数值是未使用工具时的大概 2 倍。
阅读源码发现 Camera 实际上渲染了两次,一次用作取样,一次用作显示。取样是用于计算 OverDraw 比率。
但是实际上还是会少算一次,因为默认情况下根据不同的 Unity 版本可能会有一次 Blit(Unity 5.6.6f2 默认强制开启 Blit),用于将当前渲染的结果送到屏幕上,以解决分辨率不同的问题。
其他参数是什么意思?
信息面板中以下属性是什么意思?
- 特效原填充像素点
- 特效实际填充像素点
- 平均每像素overdraw率
阅读代码发现原理是将相机渲染到一张 512x512 的 RenderTexture
,然后计算有颜色的像素数量,以及有颜色的像素重复渲染次数,取平均值显示,同时计算比率。
打包时有编译错误
因为运行时脚本中存在 using UnityEditor;
声明,理论上来说此工具并不需要打包到最终版本中,因此将使用到的运行时脚本使用 UNITY_EDITOR
宏定义完全包围,这样就不会影响打包。
缺失功能
ParticleSystem 数量
使用 GetComponentsInChildren(true)
获取数组,然后直接打印组件的数量即可。
注意:一定要包含未启用的 ParticleSystem 组件,防止统计有误。
贴图 数量
在遍历获取贴图大小时,可以一并将其计数返回。
注意:考虑到特效中使用的不同 ParticleSystem 可能会引用相同的贴图,因此在遍历时必须去除重复。
操作优化
实际使用工具时是先添加脚本后再运行的,这样导致 Prefab 上增加了一个无用的脚本。
不过如果未去除 ParticleEffectScript
脚本就点击 Prefab 的 Apply 按钮保存则工具会报错。
但是实际上美术在使用工具时偶尔会遗忘,从而导致 Prefab 资源被无用脚本污染。
解决方案是使用播放状态变化事件以及编辑器自身的 Update 事件去检查是否进入到播放状态,决定是否添加测试脚本。
注意:InitializeOnLoad
会在播放后重新触发,因此无法通过静态变量的方式保存测试开始的请求状态,因此使用 EditorPref
保存请求状态。
注意事项
- 需要新建特效性能评估专用场景,调整好相机的视角、距离与 Clear Flags,用作基准,在之后的测试中尽量不发生变化,否则结果不便比较。
- 只能在场景中放置一个要测试的特效,不能放入其他特效导致结果被污染。
优化
以下列出了一些比较好但未实现的需求,如果时间允许或其他人有兴趣可以考虑实现:
- README 文档更新,详细介绍工具功能以及背后原理,方便他人使用。
- 每一项数据如果有超过推荐值则应显示为红色。
- 导致无法裁剪的列表中只显示特效名字而未显示路径,其实最好显示
ObjectField
,这样可以直接点击跳转到对应的GameObject
。 RenderTexture
与Texture
需要缓存起来,不要每帧都分配。- 使用
string.Format
与StringBuilder
格式化字符串,减少内存消耗。 - 浮点数比较去除直接比较,防止丢失精度与产生警告。
- 字体需要修改为系统自带的字体,同时调整字号。
- 使用命名空间重新组织代码,重新命名脚本。
- 项目结构不太合理,可以考虑不作为一整个 Unity 项目,而作为 Unity 中的一个单独插件目录管理,例如 NGUI。
- 应该正确设置屏幕分辨率,需要与目标设备的最流行分辨率一致。
工具
更新 20190729
Pull Request 已合并到上游
文章作者 狂飙
初次发布 2019-07-28 23:36:25 +0800
永久链接 https://networm.me/2019/07/28/unity-particle-effect-profiler/