找回密码
 立即注册
查看: 283|回复: 0

【性能优化】汇总篇

[复制链接]
发表于 2022-4-14 21:34 | 显示全部楼层 |阅读模式
前言

整天在讲性能优化,今天学习了一下课程,发现我一无所知
以下内容是 Unity官方的 OptimizeYourMobileGamePerformance 电子书的阅读笔记
1. Profiling




使用时间轴视图来确定您是受 CPU 限制还是受 GPU 限制。

可以使用Unity自带的Profiling定位是CPU瓶颈还是GPU瓶颈

  • 如果您看到Gfx.WaitForCommands标记,则表示渲染线程已准备好,但您可能正在等待主线程上的瓶颈。
  • 如果你经常遇到Gfx.WaitForPresent,这意味着主线程已经准备好但正在等待 GPU 呈现帧。
Profiling分析方法1:在优化项目中的任何内容之前,请保存 Profiler.data文件。实施您的更改并比较修改前后保存的.data 。依靠这个循环来提高性能:分析、优化和比较。然后,冲洗并重复。
Profiling分析方法2:Profile Analyzer
2. Memory

Unity 对用户生成的代码和脚本采用自动内存管理。

  • 小块数据,如值类型的局部变量,被分配到堆栈中。
  • 更大的数据和更长期的存储被分配给托管堆。
垃圾收集器定期识别和释放未使用的堆内存。虽然这会自动运行,但检查堆中所有对象的过程可能会导致游戏卡顿或运行缓慢。
优化内存使用意味着要注意何时分配和释放堆内存,以及如何将垃圾收集的影响降至最低。有关详细信息,请参阅了解托管堆。
内存分析工具:Memory Profiler
3. Adaptive Performance

这个插件,在包管理器可以下载到,主要用来做不同机型的兼容
其实代码也都能写,就是工具造好轮子了,不用重复造轮子
教程:Code Lab |  Samsung Developers
Unity文档:Using Adaptive Performance samples
功能:

  • 自适应FPS
  • 自适应质量设置
  • 提供模拟器
  • 通过识别设备性能状态和发热趋势,可以实时调整游戏性能和质量设置。
例子:



例子

4. Programming and code architecture(编程和代码架构优化

了解 Unity PlayerLoop






脚本生命周期流程图

删除调试日志语句

日志语句(尤其是在UpdateLateUpdateFixedUpdate 中)可能会降低性能。在进行构建之前禁用您的


Player Settings中禁用ENABLE_LOG预处理器,您的所有Log语句都会一举消失。
使用哈希值而不是字符串参数

Unity 在内部不使用字符串名称来处理 Animator、Material 和 Shader 属性。为了速度,所有属性名称都被散列到属性 ID 中,这些 ID 实际上用于对属性进行寻址。
在 Animator、Material 或 Shader 上使用 Set 或 Get 方法时,利用整数值方法而不是字符串值方法。字符串方法只需执行字符串散列,然后将散列后的 ID 转发给整数值方法。
使用Animator.StringToHash作为 Animator 属性名称,使用Shader.PropertyToID作为材质和着色器属性名称。
举个例子:比如 animator.SetTrigger("h_moveDir"); rider会提醒用静态int去优化:
private static readonly int s_HMoveDir = Animator.StringToHash("h_moveDir");
animator.SetTrigger(s_HMoveDir);
选择正确的数据结构

Collections and Data Structures
5. Project configuration

Avoid large hierarchies 避免预制节点太多

节点太多会消耗引擎检查节点的CPU时间
视频:Unite Berlin 2018 - Unity's Evolving Best Practices
Transform once, not twice

如果需要同时设置位置和旋转,可以用Transform.SetPositionAndRotation 接口,避免访问transform2次
比如生成GameObject,并初始化的时候,可以直接用GameObject.Instantiate(prefab, parent, position, rotation);减少Transform的多次访问
6. Assets

Arm 和 Unity 联合推出:适用于移动应用程序的 3D 美术优化
Import textures correctly

纹理占用的内存非常多,所以正确的导入设置非常重要

  • 尽可能减小最大尺寸
  • Use powers of two (POT):纹理尺寸最好是2的次方幂,这样才有使用(PVRCT or ETC 2)压缩纹理
  • 打图集:Unity SpriteAtlas 或者 Texture Packer
  • 关闭Read/Write选项:开启会创建一份CPU和GPU可访问的内存备份
  • 关闭MipMap:很多2d的纹理不需要mipmap
  • 压缩格式:Recommended, default, and supported texture formats, by platform
Adjust mesh import settings


  • Compress the mesh
  • Disable Read/Write
  • Disable rigs and BlendShapes
  • Disable normals and tangents, if possible
Use the Addressable Asset System

7. Graphics and GPU optimization

Disable shadows

8. User Interface(UI)


  • 动静分离
  • 隐藏不可见元素
  • 需要GraphicRaycaster再添加,需要Raycast Target 再勾选
  • Layout Groups 是会一直update的,可以自定义组件,在排序后disable这个组件
  • 循环复用列表:GitHub - boonyifei/ScrollList: Optimizing the scroll list
9. Audio


  • 勾选force to mono(单声道):多声道音频在运行时很有可能被平衡成单声道
  • 使用未压缩的wav格式:使用MP3、Vorbis,Unity会先解压缩,然后build的时候又要再压缩一次,造成2次有损传递,最后降低音质
选择合适的Load Type


  • < 200 kb:Decompress on Load
  • >= 200 kb:Compressed in Memory
  • background music:Streaming,不然整个资源会直接加载到内存
Destory 那些没有在用的声音资源


10. Animation

Use generic VS humanoid rigs


  • 导入模型,Unity默认使用 Generic Rig ,但是开发者通常会给他转成 Humanoid Rig
  • Humanoid Rig 会比 Generic Rig  多耗费30%-50%的CPU,用来计算IK和动画重定向,如果你不需要这些功能的话,最好还是用Generic Rig
避免滥用Animation

Animator是主要设计来给人形角色用的组件
对于一些简单的动画,可以用DOTween实现,尽量不要用Animation
11. Physics

Optimize your settings


  • 勾选 Project Settings > Player > Prebake Collision Meshes



  • 尽可能简化你的碰撞矩阵:Project Settings > Physics > Layer Collision Matrix
  • Disable Auto Sync Transforms and enable Reuse Collision Callbacks.
  • 移动一个挂有Rigidbody的对象,用MovePosition or AddForceMove,直接访问Transform会导致物理时间的重计算,然后如果需要在update里刷新的话,最好是在FixedUpdate.(具体原理没写)
  • Window > Analysis > Physics Debugger,定位物理问题
12. Workflow and collaboration

拆分大场景

跟拆大预制一样,拆分场景,然后用附加的方式添加场景(LoadSceneMode.Additive)
13. Unity Integrated Success

14. Conclusion

完整看下来,这本书就是Unity的插件一览会,插件安利书,虽然有提到一些有用的,但是没讲原理,不过可以自行百度就是了,好的一点是,整理了个优化的框架,以后有新的东西,可以往里面填。
<hr/>Unity性能优化:可以从以下4个方面去讲:CPU、GPU、内存、显存

性能优化和图形硬件的关系



CPU和GPU的交互

  • 代码在CPU运行,从内存中获取数据
  • 显卡通过PCI总线插在主板上,
面试经典题1:性能调优你们都怎么做的?

定位瓶颈、理解问题、解决问题、掌握技巧
定位瓶颈
①CPU瓶颈:
打开Unity Profiler窗口,查看耗时长的函数是否正常,是否有GC Alloc,
字符串拼接用StringBuilder
序列化与反序列化(Json、XML、PB)
GetComponents、Input.Touches、Mesh.vertices等接口返回的是内存的拷贝,注意这些Get系列的函数
Debug.Log,Warning
Lambda表达式、匿名函数、Linq
Camera.main:GameObject.FindObjectWithTag("MainCamera")
Physics.RaycastAll==>Physics.RaycastNonAlloc
②GPU性能瓶颈:
States窗口,看Batches(DrawCall合批次数)、SetPassCall(CPU往GPU发送命令数量),3D模型、UGUI
③其他:物理
面试经典题2:UI卡顿你们是怎么解决的?

Canvas优化要点

  • 动静分离:UI界面很复杂的话,要划分更多的子Canvas,因为一个Canvas下的所有元素都是合成在一个mesh进行渲染的,过大的mesh更新时开销很大,拆分频繁变化的部分自成一个Canvas,这样刷新的时候就不用刷新不变化的部分,减少性能消耗
  • 一个面板的UI资源放同一个图集
  • 大预制拆分成子面板
OverDraw(GPU)

  • 造成GPU性能瓶颈原因:复杂的顶点或者像素计算、OverDraw(光栅化阶段填充像素过多)
  • 解决方案:禁用不可见UI、不要使用空Image==》EmptyRaycast
  • 少用LayoutGroup或者ContentSizeFitter==》自己写算法自己算
  • Layout原理:遍历SetDirty对象会消耗性能
面试经典题3:模型优化有什么好的办法?


  • 蒙皮网格动画==》顶点动画【空间换时间】
  • Animator LOD【远处动画降帧】
  • Animation Instancing【比如一堆一样模型的士兵、花草树木等】
  • 慎用MeshCollider【低模或者改用胶囊体】
  • 静态合批:Mesh.CombineMesh()【空间换时间】
  • 动态合批:骨骼蒙皮、GPU Skinning
  • 地形:Terrian==>Mesh、MMO分区域地图、动态加载卸载、接缝处理
  • 纹理贴图:Mipmap、三线性插值、注意半透明优化
  • 定位Shader瓶颈
  • 关闭不用的碰撞矩阵
  • 定时主动GC
  • 不用的资源要销毁或释放,需要的资源要缓存
  • 尽量异步加载、防止阻塞
面试经典题4:UI优化:文本优化:TextMesh Pro



参考

CPU与GPU协同工作_豌豆射手的专栏-CSDN博客
Unity_eBook_OptimizeYourMobileGamePerformance_V6_May2021.pdf
Optimize your mobile game performance: Tips on profiling, memory, and code architecture from Unity’s top engineers | Unity Blog

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-15 06:59 , Processed in 0.090117 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表