造成游戏性能瓶颈的主要原因分成以下几个方面:
(1)CPU
1.过多的 draw call
2.复杂的脚本或者物理模拟
(2)GPU
1.顶点处理
过多的顶点、过多的逐顶点计算
2.片元处理
过多的片元(既可能是由于分辨率造成的,也可能由于overdraw 造成的)、过多的逐片元计算。
(3)带宽
1.使用了尺寸很大且未压缩的纹理
2.分辨率过高的帧缓存
针对上面的内容会涉及的优化技术:
(1)CPU 优化
1.使用批处理技术减少 draw call 数目
(2)GPU 优化
1.减少需要处理的顶点数目
优化几何体、使用LOD及遮挡剔除
2. 减少需要处理的片元数目
控制绘制顺序、警惕透明物体、减少实时光照
3. 减少计算复杂度
使用Shader的LOD技术、代码方面的优化
(3)节省内存带宽
1.减少纹理大小
2.利用分辨率缩放
可以利用Unity提供的一些渲染分析工具来实现
1、降低屏幕分辨率尤其是在android平台对性能提升很大。可以有效缓解gpu的压力。
2、做好资源异步加载,实现一个实例化队列,可以很大程度上减少卡顿。
3、做好超量的模型和特效屏蔽,可以有效减轻cpu压力。
4、善用工具。比如Unity Profiler、Snapdragon Profiler等,针对性的对性能瓶颈进行优化。
5、玩家头顶血条的HUD要使用3D的,而不是UGUI。否则同屏玩家数量很多的时候Mesh合并开销很大。
6、UI上使用TextMeshPro。可以很大程度上缓解UI打开卡顿的问题。描边、阴影开销很低。
7、控制帧率。现在高刷新率的手机非常多。不要直接使用VSyncCount控制帧率了。否则在120hz刷新率的手机上vSyncCount=1会有120fps的帧率。直接使用targetFrameRate=30来设置帧率。
8、利用分辨率缩放,具体可参考设置屏幕分辨率
(一) UI的性能优化
1、每个图片材质都会产生一个dc, 只有通过打包图集,才能合并dc,。同个图集内的图片,dc都为1。不同图集渲染顺序的交叉会产生额外dc,所以界面尽量按图集整理UI顺序
2、实现一个高效率的 FindChlid 函数。因为在写UI的时候查询控件对象是非常常见的操作。如果不做优化,使用 gameObject.name == “xxx” 来做比对的话,可能会产生很多的GCAlloc。
3、血条的减少动画之前是Image和DOTween来实现的。后面修改为shader实现。(坐标计算)
4、小地图用shader实现指定位置的图片渲染,而不是RectMask2D,可以减少overdraw。因为RectMask2D是使用alpha=0来实现裁剪的。
5、小地图的玩家标识,聊天界面,都添加Canvas,目的是动静分离。
6、UGUI的合批规则是自动计算元素的层级。先排除掉active=false,使用scale=0或Canvas Group=0
(二) 场景的性能优化
1、要勾选StaticBatch,但是不能滥用。有color、uv3的,顶点超过4000个以上的,数量超多,但是同屏显示不多的模型。这些都不应该勾选StaticBatch。否则会导致包体积明显增大。因为StaticBatch会把模型都build到场景的ab包内。
2、避免模型和贴图勾选 readable选项。这个可以在模型和纹理导入的时候做设置。
3、对于多个模型使用共享材质,应用Renderer.shareMaterial 来保证修改的是和其他物体共享的材质,
4、使用动态批处理时需注意顶点属性规模(超900顶点)、保证指向光照纹理中的同个位置、多Pass的shader会中断批处理(前向渲染中,需要使用额外的Pass为模型添加更多的光照,确保模型不会被动态批处理)
(三) 一般优化
1、按ID寻址属性。比如 Animator、Shader都有对应的接口。Animator.StringToHash。Shader.PropertyToID。
2、减少矢量和四元数的数学计算。控制运算顺序。尽可能不要使用分支语句和循环语句
3、隐形颜色字符串转换的时候 (#RRGGBBAA),使用一个 ColorUtility 的API会更加高效,且可以避免GCAlloc。
4、调试代码可以增加 [Conditional(“DEBUG”)] 这样的标签。防止开发版本的代码或者日志发布出去。频繁打Log会对性能有严重影响。
5、对象的Update放到统一的管理器或主线程里面进行更新。
6.、避免使用昂贵的数学函数。比如 pow exp log cos sin tan 等。可使用查找表来作为替代
7、运用对象池,避免重复实例化、分帧运算,避免短时超负荷、数据缓存,避免重复运算及算法
(四) Shader的性能优化经验
1、尽可能减少纹理采样数目,控制绘制顺序、时刻警惕透明物体、减少实时光照和阴影
2、优先使用低精度的数字格式。优先使用half。在现代gpu上fixed等同于half。 部分对精度有特殊需求的情况下才使用float。个别情况下,尤其是与法线相关的时候,使用half容易因为精度不足导致渲染结果错误,这个时候还是应该使用float。
1、CPU
运用对象池,避免重复实例化
分帧运算,避免短时超负荷
数据缓存,避免重复运算
算法
2、 GPU
使用多层次细节LOD
使用光照贴图
静态合批和动态合批
简化着色器
使用平台推荐的压缩格式
减少模型面数
减少贴图大小
3、内存
模型区分高低模
释放AssetBundle
降低模型面数
降低骨骼数量
降低贴图大小
4、 包体
压缩图片
压缩音频
压缩自带库文件
拓展包
分段下载
5、 网络
数据流量优化