优化技术专题

# 性能优化工具

# 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 并定期监控游戏性能,将帮助你创建更加流畅、优化良好的游戏体验。

上次更新: 2025/02/10, 20:20:37
最近更新
01
Git问题集合
01-29
02
安装 Nginx 服务器
01-25
03
安装 Docker 容器
01-25
更多文章>
×
×