思考或者解决一个问题,需要进行系统性分析(系统/结构化思维)。以前项目开发过程中陆陆续续做了一些关于游戏应用程序性能优化的记录,但是一直以来没有进行系统性的整理,所以写这篇文章也是为了复习巩固这些知识。并没有面面俱到,只是贴合项目经历,呈现自己印象深刻的一些内容。
培养和应用结构化思维处理问题对心理层面也有积极的意义,由于其基于对问题解构分析(不提前给出可能或者不可能的结论),打破了对未知的恐惧,自我怀疑和不自信。而这些现象的本质是认知局限导致的思维定势(这一点很多人都意识不到,但却极大影响了我们的人生)。
首先从冯•诺依曼存储式计算机工作原理的角度,可以将优化问题分为两大类:
- IO密集
- 计算密集
目前业界大多数应用场景相对来说IO密集是瓶颈,而计算资源则相对富裕(游戏程序二者相对均衡)。但是反过来,IO密集的优化策略却是比较确定的,而计算密集的策略更灵活(现实中,存储资源更经济,只是触发IO行为本身是不经济的,很有点辩证的味道)。
从经济学角度来看,人类的一切行为都可以理解为经济问题,即对资源的利用问题,而计算机资源的利用可以分为以下五个大的方面。
需要指出的是,除了使用那些更先进的策略,有一些优化则是取舍的问题,比如涉及到时间与空间的换算,根据实际场景来抉择。PS:由于有的项目整合了ToLua框架,所以代码相关部分也包含了Lua语言。
一,包体
单独写了一篇进行阐述:Unity游戏性能优化_包体。
二,内存
单独写了一篇进行阐述:Unity游戏性能优化_内存。
三,GPU
- 3D物体
- 面数 500-3000,重要对象可以适当放宽到6000-10000面
- 考虑视角锁定,模型背面简化,远处不可到达则低模或者面片
- Mesh尽可能结合,大地表则必须切割动态加载
- Material 和Texture 尽可能共用
- 一个Mesh最好只用一个Material,特殊角色2~3个也够了
- 使用不同的Material的原因,是想要使用不同的shader
- 一个Mesh只使用一个SkinnedMeshRenderer(大批量复制对象需处理为支持GPU Instancing)
- 涉及换装的部分,Material应该要分开
- 骨骼数量:15~60 之间
- 带宽与显示效果(Mipmap/LOD)
- 贴图
- 少用透明贴图
- 动画复杂度
- 采样帧率
- 参数精度
- 冗余属性
- 粒子特效规范
- 少用,多考虑动画
- 发射对象:贴图小,模型简单
- 发射规模小
- 使用默认自带的particle类shader
- 光照相关设置全关闭
- HDR取消
- 光照:预烘焙
- Shader:通道,数据类型定义与陈列顺序
- Overdraw:动静分离
- 渲染批处理(静态/动态/Gpu Instancing)
- 渲染路径 Forward+,延迟渲染
- 渲染引擎 Vulkan(面向多核架构)
四,CPU
主要职责:渲染资源的状态设置和提交,Drawcall调用(移动平台以150为准),复杂计算(物理/AI)等
- IL2CPP与Mono虚拟机,现在Android也可以IL2CPP(Googleplay强制要求支持64位系统,而Mono并不支持64位编译)
- C#脚本
- for not foreach(内存开销更大,考虑到数量级的情况下)
- Lua脚本
- 支持JIT即时编译
- 减少全局对象
- 开销大的部分由C#层实现,比如网络通信
- C#与Lua交互
- 胶合层代码尽可能少
- 复杂数据类型少:GameObject/VectorX等
- Lua与C#互操作接口尽可能简单
- 业务逻辑算法
- 编码解码
- 协程/多线程
- 寻路策略:路点,A*,NavMesh
- 分帧处理
五,IO/网络
- 资源打包颗粒度
- 资源IO总量
- 数据包压缩
- 数据加密方式
- 通信频次
- CDN缓存优化
- 负载均衡(服务端)
参考:IO密集问题的简要理解
六,发布设置
- 物理:3D模式时可以关闭Physics2D
七,工具
-
- Unity Editor Profiler
- UPR
- UWA
- Xcode Instruments
- RenderDoc
- Mali Graphics Debugger
- LuaProfiler
- TaskManager(Win) / Activity Monitor(Mac)
PS:继续完善中。。。