优化技术专题
# 性能优化工具
# Stats 工具重要参数详解
Audio:
Graphics: 102 fps(最高可以达到的帧数)
CPU:
main(主线程做一次循环需要的时间) 1.6ms。
render thread (绘制相关的花费的时间) 1.1ms。
Batches: 2 整个游戏场景里面的物体,分几批来进行绘制的。就是说物体第一批提交给显示,第二批提交给显卡。直到把整个场景绘制完毕。Bache 就是 Drawcall。
Saved by batching: 978 表示场景中有多少个物体被分批渲染了。
Tris: 1.7K 总共有多少个面。
Verts: 5.0K 总共有多少个顶点。
Screen: 1024x768 -9.0M 指的是屏幕的分辨率。
SetPass Calls:2 指的是配置渲染管道 Shader 参数的次数。这个也是非常消耗性能的。
Shadow Casters:0 阴影产生的性能消耗。这个开销也能够加大Batchs。
Visible skinned meshes:0 可见的蒙皮网格。也是非常消耗性能的。
Animations:0 动画开销。这个也是非常消耗性能的。因为每个动画都要重新绘制顶点。
注:场景摄像机中的背景色和天空盒各占一个 Batching。
# Profiler 工具重要参数详解
CPU的性能情况:
Rendering:渲染
Scripts:C#脚本代码的消耗
Physics:物理消耗
Vsync:垂直同步,关闭后性能会好但是画面会开裂。
Others:其他
下面的列表会列举出排在前面的性能消耗:
Total Self Calls GCAlloc Time
Self = Total - 其他消耗,这两个是非常重要的性能指标。
Self * Calls = 总共消耗的性能。解释:每次调用的时间 * 调用的次数 = 总共消耗的时间。
Render:的性能情况
Set pass call 、draw call 、total batchs 、面数 、顶点数
动态合批:
静态合批:
Instancing合批:
Used Textures:
RenderTextures:
Screen:
vram usage:
Vbo total:
Vb uploads:
GC Allocations:
# UGUI Drawcall 优化
# 什么是 Drawcall
CPU 调用计算机图像编程接口,以命令 GPU 执行渲染操作。
游戏场景里的物体分几个批次提交给 GPU,就有几个 Drawcall,这个东西越少你的游戏跑的就越快。查看 Drawcall 的方式,Stats 和 Profiler。一次提交的比较多,CPU 提交的性能也会比较好,GPU 也每次都能 "吃饱"。
# 如何做 Drawcall 优化
- 首先要分析 Drawcall 的来源,是谁占用了 Drawcall。
- 默认情况下是相机背景和相机天空盒各占用1个。
- 运行时隐藏节点(物体),在分析工具中也能发现 Drawcall 数量变化。
- 物体和阴影也会影响 Drawcall。
- Text 组件对 Drawcall 的影响。
- 文本 Text 的核心原理:通过 Text 组件 + 矢量字库 + 字体大小 + 文本内容 生成一个文字贴图,底层会将文本以贴图的形式来对待。
- 文本 Text 底层使用的 UI/Default 这种 Shader,但是文本动态的文字纹理和图集肯定是不一样的,所有文本的纹理会动态的合并成一张纹理图集。如果两个文本的字体不一样,Drawcall 就会增加。
- Unity3d 场景是按照场景树来绘制的,这样 Text 会打断纯图集的 Drawcall,但是 Unity3d 做了一个优化,Text 并不会打断图集的 Drawcall。如果 Text 不影响其他 UI 的绘制,Text 的Drawcall 会进行合并。如果 Text 影响了其他 UI 的绘制,Text 的 Drawcall 将不进行合并。
- RawImage 对 Drawcall 影响
- Image 优点是简单并且可以合并 Drawcall。
- RawImage 优点是可以修改纹理贴图的 UV,但即使这个图片在一个图集,也无法合并 Drawcall。每增加一个 Rawimage 就增加一个 Drawcall。除非使用的是同一个 Shader 和同一张图片。
- OnGUI 对 Drawcall 的影响
- 每添加一个 OnGUI 就会增加一个 Drawcall。
分析工具提示
Save Baches 统计的是 Dynamic batching 、 Static batching 、 Instancing 这三种东西。
- Drawcall 优化
- UGUI 打成图集,可以降低 Drawcall。
- 将 UGUI 做成批处理。
两个物体能否在一批的条件
- 模型相同:UI 的模型都是矩形。
- Shader 相同:UI/Default。
- 纹理类型相同:Image 纹理参数不一样,所以没有合并到一个 Drawcall。将分开的小图片打成一个大图集可以使 Iamge 纹理参数一样,这就是图集可以降低 Drawcall的原因。
# 如何制作 UGUI 图集
- 编辑器 Setting 中找到 Sprite Packer:启用 Always Enable。
- 你要打包哪些图片到哪个图集?先新建一个图集名称,一般将一个文件夹下的图片打包到一个图集。(图片资源放置时就事先归好类)
# Unity是一款非常强大的游戏引擎,但在处理大型场景或复杂模型时,它也会遇到性能问题。以下是一些可以优化性能的常见方法:
减少三角形数量:减少游戏中的多边形数量可以大幅提高性能。使用低多边形模型、合并网格和使用LOD(Level of Detail)技术等方法可以有效地减少三角形数量。
使用纹理压缩:纹理压缩可以减小资源文件的体积,从而减少加载时间和内存开销。Unity支持各种纹理压缩格式,包括ASTC、ETC、PVRTC等。
禁用不必要的组件:当游戏对象上存在不必要或无用的组件时,会占用系统资源并降低性能。因此应该及时禁用这些组件。
使用轻量级的物理引擎:物理引擎可以增加游戏真实感,但是过于复杂的物理计算会影响性能。使用轻量级的物理引擎可以达到更好的性能效果。
避免频繁的GC:频繁的垃圾回收(GC)会占用CPU资源和导致游戏卡顿。使用对象池、避免过多的实例化和销毁等方法可以减少GC次数。
使用批处理技术:批处理可以将多个渲染操作合并成一个,从而减少GPU的负载。使用静态批处理、动态批处理、合并网格等技术可以提高游戏性能。
使用合适的平台设置:Unity支持多平台开发,但是不同平台的硬件配置和性能差异很大。因此在开发时需要根据目标平台做出相应的调整,例如降低分辨率、调整帧率、使用雾效果等。
# 常见的一些优化方法,分为多个领域来详细探讨
1. 渲染优化
1.1 减少 Draw Calls
- 合并网格:如果场景中有多个小物体且它们使用相同的材质,可以将这些物体合并成一个大网格,这样就能减少 Draw Calls。
- 静态合批:对于不移动的物体,使用静态批处理(Static Batching)将它们的网格合并。你可以在 Inspector 中勾选 Static,让 Unity 自动合并。
- 动态合批:对于动态物体,使用动态批处理。Unity 会自动将小的物体合并成一个大网格,减少渲染调用次数。使用 Static 和 Dynamic Batching 时要注意网格的大小和材质数量。
- 剔除不可见物体:通过视锥体剔除(Frustum Culling) 和 遮挡剔除(Occlusion Culling),只渲染摄像机视野内的物体。Unity 会自动做视锥体剔除,但可以根据需要使用遮挡剔除。
1.2 减少材质切换
- 每切换一次材质都会触发一次 Draw Call,因此尽量避免使用多种材质。尽量将多个物体使用相同的材质。
- 使用 纹理图集(Texture Atlas)将多个小纹理合成一张大纹理,减少材质切换的次数。
1.3 优化光照
- 使用 烘焙光照:尽量使用烘焙光源(Baked Lighting)而不是实时光源(Real-time Lighting)。尤其是对于场景中不需要动态光照的物体,烘焙能显著减少计算开销。
- 减少实时光源数量:对于实时光源,可以通过调整其范围或开关其影响来减少计算量。尽量避免使用多个动态光源,尤其是阴影较重的光源。
- 混合光源:可以使用混合光源,部分光源作为实时光源,部分光源作为烘焙光源。
1.4 减少阴影
- 优化阴影设置:阴影计算是一个性能开销大的操作,可以考虑使用 低分辨率阴影贴图,或者只为重要的物体启用阴影。
- 减少阴影数量和范围:减少场景中阴影的数量,控制阴影的分辨率、范围等参数,避免给不重要的物体添加阴影。
2. 物理优化
2.1 减少物理计算
- 避免不必要的碰撞体:如果某些物体不需要参与物理计算,可以通过禁用其 Collider 或将其设置为触发器(Trigger)来减少物理计算。
- 简化碰撞体:使用简单的碰撞体(如球形、盒形、胶囊形等),避免使用复杂的网格碰撞体(Mesh Collider)。对于非动态物体,使用 静态碰撞体。
- 调节物理步长:物理引擎的更新频率可以通过 Time.fixedDeltaTime 调节。适当增加 fixedDeltaTime(例如从 0.02 秒调整到 0.05 秒)可以减少物理计算的开销,但要小心可能导致物理模拟不准确。
2.2 使用物理层和碰撞过滤器
- 使用物理层(Layer)来过滤碰撞体,避免不必要的碰撞检测。比如,敌人和玩家之间的碰撞可以只在特定的层上进行计算,避免与环境的碰撞计算。
3. 内存优化
3.1 减少内存分配
- 在游戏运行时尽量避免频繁分配和销毁对象,避免频繁调用 new 和 Destroy,这会产生大量的内存分配和垃圾回收。
- 使用
对象池
来重用对象,尤其是对于频繁创建和销毁的对象(如子弹、敌人等)。
3.2 资源管理
- Asset Bundles 或 Addressables:使用 Asset Bundles 或 Addressable Asset System 来加载资源,这样可以按需加载资源,而不需要一次性加载所有资源。
- 卸载不使用的资源:手动卸载不再使用的资源(如通过 Resources.UnloadUnusedAssets()),并注意避免加载不需要的资源。
3.3 避免内存泄漏
- 定期检查内存使用情况,确保没有丢失引用的对象未被正确回收,尤其是在调用 Destroy() 时。
- 使用 Unity Profiler 和其他工具(如 Memory Profiler)来监控和诊断内存泄漏问题。
4. 脚本优化
4.1 避免频繁调用 Find 系列方法
- GameObject.Find 和 Transform.Find 是性能开销较大的操作,尤其是在每帧调用时。尽量避免在 Update() 中频繁调用它们。
- 将对物体的引用缓存下来,在启动时查找一次,后续使用缓存的引用。
4.2 优化 Update()
- 减少不必要的 Update() 调用:避免每个物体都实现一个 Update() 方法。如果某些对象不需要每帧更新,可以考虑使用 InvokeRepeating() 或协程(Coroutine)来代替 Update(),或根据需要调整其调用频率。
- 将不需要每帧调用的逻辑放到 FixedUpdate 或 LateUpdate 中,避免不必要的计算。
4.3 避免频繁的字符串拼接
- 在游戏中避免在每帧频繁进行字符串拼接。字符串拼接会生成大量新的字符串对象,这会增加垃圾回收的压力。可以使用 StringBuilder 或将字符串拼接操作集中在某些较少发生的时刻。
4.4 减少多次调用重计算方法
- 例如 Vector3.Distance() 这种方法,如果在一帧内多次调用,计算代价可能较高。尽量缓存结果,避免多次调用相同的计算。
5. 其他通用优化技巧
5.1 使用 Profiler 和分析工具
- 使用 Unity Profiler 监测和分析性能瓶颈,找到哪些部分消耗了大量的 CPU、GPU 或内存。
- 使用 Memory Profiler 监控内存使用,发现内存泄漏或资源浪费。
5.2 减少场景中的物体数量
- 合并物体:对于不需要单独控制的多个小物体,考虑合并为一个大的物体。
- 分割场景:对于大场景,考虑将其分割成多个小场景,按需加载和卸载。
5.3 按需加载和卸载资源
- 动态加载场景资源和关卡数据,避免一次性加载过多资源。使用 SceneManager.LoadSceneAsync 来异步加载场景和资源。
总结:
优化性能是一个持续的过程,需要根据具体的游戏需求和平台来进行优化。关键的步骤是: 减少渲染
和物理计算
的开销、减少内存分配和垃圾回收
、以及 高效管理资源
。通过 Unity 的 Profiler 和其他优化工具,你可以更准确地找到性能瓶颈,进行有针对性的优化。
# Profiler使用概述
一、面板概述
Profiler 窗口由多个标签页组成,每个标签页显示不同的性能数据。常见的标签有:
CPU Usage:显示 CPU 使用情况,包括每个线程的消耗、每帧的计算开销等。
GPU Usage:显示 GPU 渲染的性能指标,帮助你查看 GPU 在渲染时的开销。
Memory:显示内存使用情况,帮助你找到内存泄漏、内存分配的高峰等。
Rendering:显示与渲染相关的数据,如绘制调用(Draw Calls)、三角形数量、材质数量等。
Audio:显示音频相关的性能数据,帮助你优化音频资源的使用。
Network:显示网络相关的性能数据,适用于联网游戏。
Physics:显示物理引擎的性能数据,帮助优化碰撞体、刚体等物理计算。
Timeline:显示各个系统(如脚本、渲染、物理等)在时间轴上的执行情况,可以帮助你定位性能问题。
Deep Profile:这是一个更细致的模式,帮助你查看每个方法的调用栈,但会增加额外的性能开销。
二、常用标签页详细介绍
2.1 CPU Usage
CPU Usage 是 Profiler 中最常用的标签之一,显示 CPU 的使用情况。它提供的信息包括:
Total Time:每帧的总 CPU 时间(包括游戏逻辑、渲染、物理计算等所有操作)。
Main Thread:主线程的使用时间。
Other Threads:其他线程的使用时间(包括渲染线程等)。
Timeline View:显示各个线程在每帧的运行时间,可以通过这一视图找到具体的性能瓶颈。 在 CPU Usage 窗口中,你会看到一个逐帧的 CPU 时间柱状图,以及下方的详细信息:
Hierarchy(层级视图):显示各个函数调用的树状图,你可以看到每个函数的执行时间。 Samples(采样数据):显示调用堆栈的统计信息,可以帮助你查看哪些方法占用了最多的 CPU 时间。
优化建议:
通过查看哪些方法在每一帧中占用 CPU 时间最多,找出性能瓶颈。
使用 Deep Profiling(深入分析)来查看每个函数的细节,但要小心它会增加性能开销。
优化频繁调用的函数,特别是 Update() 中的内容,避免每帧做大量的计算。
2.2 GPU Usage
Total GPU Time:每帧的 GPU 总时间。
Main Thread:显示 GPU 渲染主线程的时间。
Render Thread:显示渲染线程的时间。
GPU Time:显示 GPU 具体的渲染操作时间,如绘制调用(Draw Calls)和后处理效果等。
优化建议:
如果 GPU 时间很长,可以查看哪些渲染操作占用了大量时间。
优化 Draw Calls 数量,减少不必要的物体渲染。
使用 纹理图集(Texture Atlas) 来减少材质切换,优化渲染过程。
2.3 Memory
Memory 标签页显示游戏的内存使用情况,包括:
Total Reserved Memory:Unity 为场景保留的总内存量。
Total Used Memory:实际使用的内存量。
Textures:显示纹理占用的内存。
Meshes:显示网格占用的内存。
Scripts:显示脚本相关的内存使用情况。
优化建议:
查看内存中使用最多的资源,确定是否有不必要的大型纹理、网格等资源。
检查是否存在内存泄漏,尤其是在动态加载和卸载资源时。
使用 Asset Bundles 或 Addressables 来按需加载资源。
2.4 Rendering
Rendering 标签页显示渲染过程的相关数据,包括:
Draw Calls:每帧的绘制调用次数。每一次绘制一个物体都会消耗一定的 GPU 时间,减少 Draw Calls 可以显著提升性能。
Batches:显示批处理的数量,Unity 会将多个物体合并成一个批次,减少绘制调用。
Tri Count:每帧绘制的三角形数量,减少三角形数量可以优化 GPU 渲染性能。
SetPass Calls:显示材质切换的次数,每次切换材质都会导致一个 SetPass 调用。
优化建议:
合并网格:多个物体可以合并为一个网格,减少 Draw Calls。
静态批处理:对静态物体启用 Static Batching,减少动态物体的绘制调用。
动态批处理:通过优化场景中的物体数量和材质,减少动态物体的绘制调用。
2.5 Timeline
Timeline 标签页提供了一个时间轴视图,显示不同系统(如脚本、渲染、物理等)在每一帧的执行情况。你可以通过它更清晰地了解每个操作的执行时间。
优化建议:
使用 Timeline 查看每个系统的执行时序,检查是否有不必要的延迟。
通过调整脚本中的执行顺序、优化复杂操作,减少每帧的开销。
三、如何使用 Profiler 进行性能分析
3.1 性能数据采样
在 CPU Usage 标签中,可以点击 Record 按钮来开始采样数据。
你可以在运行游戏时实时查看各项数据,并通过 深度分析(Deep Profiling) 查看每个方法的执行时间,进一步找到性能瓶颈。
3.2 分析并优化瓶颈
通过查看哪些函数调用占用的时间最多,找出性能瓶颈。例如,脚本中的 Update() 方法、物理计算、渲染等。
通过查看每个线程的使用情况,识别是否存在主线程阻塞或 GPU 渲染瓶颈。
3.3 数据对比
rofiler 允许你将不同的帧或不同的场景进行对比,查看优化前后的性能变化。你可以通过 录制多个帧 来查看游戏在不同时间段的表现。
3.4 使用 Profiler 远程连接
如果你正在调试移动设备或其他外部平台上的游戏,可以通过 远程连接 使用 Profiler。在 Unity 编辑器的 Profiler 窗口右上角选择 Active Profiler,然后连接到移动设备进行实时分析。
3.5深入分析和优化流程
使用 Profiler 找到瓶颈:首先通过 Profiler 找到性能瓶颈,例如 CPU、GPU 或内存上的问题。
优化特定模块:针对具体的瓶颈进行优化,比如减少 Draw Calls、减少内存占用、提高算法效率等。
持续监控:优化后使用 Profiler 再次测试,确保优化有效且没有引入新的问题。
四、总结
Unity Profiler 是一个强大的性能分析工具,可以帮助你精确地找到性能瓶颈并进行针对性的优化。熟练掌握 Profiler 并定期监控游戏性能,将帮助你创建更加流畅、优化良好的游戏体验。