Skip to content

性能优化参考

主场景资源限制

TIP

以下为主观测试数据,仅供参考

模块
维度

Unity Engine
模型
模型格式

fbx/obj

面数上限(同屏)
单模型
25W


总面数
125W

模型尺寸

无要求

单文件模型上限
模型数量
30

材质
类型
无要求

材质贴图
尺寸限制
1024 x 1024


文件格式
png/jpg/jpeg/tga


同屏材质数
135
动画
2D 序列帧动画
基础要求
可以自己用 shader 实现(可以用第三方插件)


帧数限制


3D 动画
基础要求



单模型骨骼上限
18
图片
图片
格式
png/jpg/jpeg/tga


最大尺寸
1024 x 1024

2D 素材压缩
是否有该功能
- 编辑器导出时自动压缩处理(android:etc ios:pvrtc)
- Unity 中可以修改 max size & compression 配置项-尽量使用不透明贴图
多媒体
音频
格式
mp3/wav


大小



其他


视频
格式
mp4/mov


大小(全景)
视内存而定,最多 2G


大小(α 通道)
视内存而定,最多 1G


大小(4K)
视内存而定,最多 3G


推荐分辨率
1080P 即可,往上性价比不高
灯光

类型
一盏平行光、烘焙点光源
特效
粒子
同屏粒子
600

透明
同屏透明对象
25

HDR
同屏 HDR 对象
100
物理

基础要求
详见 Unity 官方文档


刚体数量
25
DrawCall

极限上限
3000 后卡死
抗锯齿


支持,4xMSAA 即可,过高性价比不高
效率
内存
最大限制
<4G(内容资源占的内存,不包含算法)

帧率

推荐高于 60,动作幅度高的内容推荐高于 72
包体
包体限制(仅渲染)
最大
512M(内容资源,不包含算法)
平台限制
导入限制



导出限制



编程语言

C#

资源优化

面数优化

  • 在 Game 窗口的 Stats 渲染统计窗口选项可以查看各项性能开销数值. Tris 代表当前窗口渲染的三角面片数.
  • 通过移动 maincamera 位置可以查看不同角度内容同屏三角面数,建议在运行状态下查看该数值.
  • 素材模型三角面数过大时需要对模型面数进行优化,网上有很多教程和不同方法可以参考这里不做详细解释.

压缩贴图

  • 在 assets 中找到贴图,点选后右侧 inspector 中会显示贴图各项数据.
  • 将 MaxSize 设置为 1024 或以下尺寸,也可以选择 Compression 进行压缩. 选择完毕后点击 Apply 即可完成 Unity 内的贴图压缩. 此外也可以使用 https://tinypng.com 等工具进行贴图压缩.

GPU Instancing

  • 为 Materials 启用 GPU Instancing:在 Project window 中选中你的 Material,然后在 Inspector 窗口中,勾选 Enable Instancing 复选框。
  • 使用 GPU Instancing 可以一次渲染(render)相同网格的多个副本,仅使用少量 DrawCalls。在渲染诸如建筑、树木、草等在场景中重复出现的事物时,GPU Instancing 很有用。
  • 每次 draw call,GPU Instancing 只渲染相同(identical )的网格,但是每个实例(instance)可以有不同的参数(例如,color 或 scale),以增加变化(variation),减少重复的出现。
  • GPU Instancing 可以减少每个场景 draw calls 次数。这显著提升了渲染性能。

  • Unity 只会在 Material 使用的 Shader 支持 GPU Instancing 时,才会显示这个复选框。这些支持 GPU Instancing 的 Shaders 包括:Standard, StandardSpecular 及所有的 surface Shaders。

CPU 优化

  1. 减少 draw calls
    • 一般来说,在每一个 frame 的时间内应尽量控制您的 VR 应用不要超过以下限制:
      • Triangle 或 Vertices:50000 到 100000 个。
      • Draw calls:100 到 1000 个。
    • 减少需要绘制的对象,包括 Renderers 及 Materials 的数量。
      • 调整 Camera 的远距离裁切面来缩短需要绘制的距离,或是直接隐藏距离较远的物体。可以使用 霧化效果 让视觉上更自然,让使用者不会直接看见远方的物体忽然消失。
    • Draw call 批处理 (Draw call batching)
      • 动态批处理(Dynamic batching):对于数量众多的小型物体 (小于 900 个 vertex attributes,或 300 个 vertices) 请尽量使用相同材质,Unity 会自动使用动态批处理,减少 draw calls。
      • 静态批处理(Static batching):对于从头到尾都不会移动旋转放大缩小的物体,请将它设为 static。Unity 会尝试将它们合并成一个大的 mesh 以减少 draw calls。(注意:这会增加内存使用量)
    • 纹理图集 (Texture Atlasing)
      • 将场景中使用到的 textures 合并成一张大的 texture。藉由这个做法,让许多对象共享同一个 texture,以便于批处理。
  • 如果使用 NGUI,您可能需要重新编排 UI 的阶层,以免必须要用到一个以上的 UIPanel。
  1. 物理运算
    • 物理运算需要使用较高的 CPU 资源,大部分的情况下,并不是所有 layer 之间都需要处理物理运算。在 Edit > Project Settings > Physics 有一个各 layer 间交互作用的关系表,请依据实际需求,关闭不必要的 layer 间交互作用。
    • Raycast 消耗不少运算,且性能与射线长度及场景中 collider 类型有关。建议使用“Layer Masks”过滤掉不需要的 layer,可以减少部分运算。

GPU****优化

  1. 使用“Mobile”版本的着色器取代“Standard”版本

    • 您可以使用 Unity 中“Mobile”类别下的简化着色器(Shader)。这些着色器是专为移动装置所设计,能带来明显的性能提升。但要注意某些着色器只支持一个 directional light,而有些着色器并不支持 alphaTest 或是 ColorMask。
  2. 光源与打光

    • 实时的照明与 reflection probes 耗用大量运算资源。建议尽量避免在移动式装置上使用。在许多情况下,使用预计算的 lightmap 及全局光照(GI)可以达到相似甚至可能更好的视觉效果,并因实时运算的减少而大幅降低所需的 GPU 运算资源。
    • 打光时的阴影是另一个优化的重点。在 QualitySettings 中依照您的项目需求来调整 Shadow 的设定,特别是 Shadow Distance
  3. 其他建议与开发准则

    • 请使用 Fixed Foveated Rendering (FFR) 来降低 GPU 使用率。FFR 即,由在外围区域降低显示分辨率改善 GPU 使用性能,并保持视野中央区域的显示分辨率不受影响。由于人眼的构造与生理特性,这样的作法并不会对视觉效果造成太大的负面影响。您可使用 Wave SDK 提供的 API 设置 FFR 的强度,依照实际对画质的影响与视觉感受来调整适合的设定值。
    • 开启 Adaptive Quality (AQ) feature。AQ 开启时,系统将自动依据 CPU 与 GPU 的使用率,动态调整显示画质。依据系统实际使用情况,在运算率较高的时候,利用 Dynamic Resolution 动态降低显示分辨率,或是利用 Fixed Foveated Rendering 调降外围区域的画质。借此达到更佳的电源管理,更长的电池寿命,与更顺畅的刷新率(FPS)。
    • 简化粒子系统(particle systems),为移动装置优化美术设计,简化 3D 网格使用较少的 vertices 与较小的 textures。
    • 避免“重复绘制(overdraw)”。这是指同一个像素位置由于对象互相重迭,而被绘制了多次的情形。一个典型的例子是粒子特效(particle effect):若粒子特效使用的 texture 包含有大量带 alpha 透明度的像素,会需要耗用大量 GPU 运算资源处理碰撞侦测与重复绘制,要避免这种情况,应减少带有 alpha 透明度的像素数量。

Wave SDK设计准则与常见使用错误

  • 不要在场景中加入多余的 main camera。某些情形下由于跨平台开发的原因,开发者在 VR 场景中加入 Unity 预设的 main camera,这会造成额外不必要的 GPU 运算,因为 WaveVR prefab 已经提供有内建的 main camera。多余的 main camera 即使对最后显示结果没有任何可见的作用,仍会造成额外运算负担。开发 WaveVR 应用时应确认场景中只有使用 WaveVR prefab 原生提供的 main camera,其他多余不应存在的都应移除或停用。
  • 尽可能使用单通道渲染模式(Single pass mode)。VR 装置藉由每个 frame 分别为左右眼绘制显示影像以产生立体视觉,单次渲染能达到较好的性能。某些情况下,由于会发生显示异常而无法使用单通道渲染模式 (例如: 使用了不支持单通道渲染的着色器)。这种情况下请特别注意:不要在 Virtual Reality** Supported** 被勾选的情形下选用 Multi pass mode,您应该直接取消勾选 Virtual Reality Supported ,以免造成额外 GPU 运算。

为您的应用缩减档案大小

  • 记得压缩您使用的 textures,既能够缩减最后 build 出来的档案大小,也能降低档案读取的时间。
  • 将 Texture 压缩的图像译码工具设为 ASTC。这能藉由使用硬件译码而达到比 Unity 为 Android 预设的 ETC2 更好的性能。

Unity UGUI 小秘诀

  • 在 UGUI canvas 底下改动任何组件时,Unity 会自动重新产生 UI 的网格,这是个有点耗时的动作。所以可以试着将 UI 分组成多个 canvas,让常常变动的 UI 影响仅限于小分组之内,减少网格重建所需的时间。
  • 尽量减少使用 Layout system,建议使用 UIAnchor

程序代码撰写

  1. 为常用属性建立缓存

    • Unity 当中如果某些 Component 属性会经常被使用到,通常值得将它们缓存起来,而不要在每次需要使用的时候都呼叫 Unity API 来取用。举例来说,gameObject.transform, gameObject.renderer, Input.touches, Camera.main, Screen.width 等等,在 Unity 内部实际是通过 GetComponent() 或 FindWithTag()等具有搜索性能消耗的代码来执行,而这些 function call 的速度并不快。
  2. 避免过大的 GC 和内存 leak

    • 在 coroutine 中最好不要使用“new WaitForSeconds()”,每一次的“new”都会用掉 20 bytes GC,您可以藉由 将“new WaitForSeconds()”移出 coroutine 之外 达到相同的效果,又可以避免这个问题。
    • 不要频繁地创建或销毁物件。请设计一个 object pool,让创建的对象能够被重复使用。
    • 使用 RaycastNonAlloc 来取代 RayCastAll ,新的 API 不会额外寻址一块内存。
  3. 改善性能与体验

    • 考虑将游戏的主要逻辑运算移到另外的线程。Unity 是使用主线程,而且它的 API 并不是 thread safe,但您仍然可以开启另一个线程并把和 Unity 无关的游戏逻辑运算移到另外的线程。
    • 加载复杂场景之前,可以先切换到一个空的或相对简单的场景,避免有两个很复杂的场景同时在内存中加载。
    • SetActive() 会影响所有的 children 对象,这会消耗不少的时间。如果状况允许,可以把不需要的对象隐藏起来,移动到看不见或很远的地方。
    • 不要使用 SetActive(false) 来关闭粒子特效。建议使用 ParticleSystem.Stop() (或较早版本的 Unity 中,将 emit 设成 0)。因为粒子系统底下通常会有很多 children,SetActive() 会作用在所有 children 对象一个一个关闭,所以比较耗时。
    • 游戏中常常会同时播放多个音效,适当地预先加载避免因同一时间读取造成卡顿。
    • 避免使用 foreach,尽量使用 for 循环来代替,执行性能较佳。
    • 避免在 Update()或是每个 frame 都会呼叫的地方做 String 的运算
    • 使用 Dictionary 时,用原生型别当作 key,避免使用 string 或是其他复杂的型别 (复杂的型别使用 Equal()来进行 key 的比对,这个动作比较耗时)。
    • Monobehavior 底下的 event function,例如 Start() , Update() 等等,如果是空的,请直接将它们移除。
    • 如果可能,请使用 Array,避免 List 或是 Dictionary。
    • 当 class 设计成不会再被继承时,请加上 Sealed,这样可以稍微增进性能。

其他改善性能的小秘诀

  • Cast and Receive Shadows 在 Unity 默认是打开的,请考虑将它关闭。
  • Skinned Mesh Renderer 在目前的移动式装置 GPU 上运算起来很耗性能,请尽量避免使用。
  • 使用 animation culling:勾选这个选项,当挂有动画的对象不在可见范围时,停止或暂停播放动画。
  • Unity 的外挂动画引擎,我们推荐使用 DOTween,在我们的经验当中它的资源耗用量以及执行时的性能都比其他的 tween engine 或 legacy animation 要好。
  • 建议使用 UnityEngine.JsonUtility。 目前它是最快的 Json parser (但使用时请注意一下它的限制)
  • 请尽量 使用 AssetBundle 来取代 Resource.Load, AssetBundle 对内存的使用较节省。

其他优化条例

  1. 使用三线性过滤或各向异性过滤来处理纹理。详见 Unity 手册中的“Textures”部分获取更多信息。
  2. 实现基于网格的遮挡剔除(请参阅 Unity 手册中的“Occlusion Culling”部分)。
  3. 始终使用前向渲染路径(详见 Unity 手册中的“Forward Rendering Path Details”)。
  4. 在 OVRManager 中启用“Use Recommended MSAA Levels”。要了解更多信息,请查阅“OVRManager”。
  5. 注意在 LOD 偏移后出现过高纹理分辨率(PC 上大于 4k x 4k,移动设备上大于 2k x 2k)。
  6. 确保非静态物体具有碰撞器,并在其本身或父级链中没有丢失刚体组件。
  7. 避免使用效率低下的特效,如 SSAO、运动模糊、全局雾和视差映射。
  8. 设置适当的物理设置,例如 Sleep Threshold 值大于 0.005,Default Contact Offset 值大于 0.0l,以及 Solver Iteration Count 设置小于 6。
  9. 减少多通道着色器的使用(例如传统的高光着色器)。
  10. 在启动场景中限制大纹理和预制件的使用,以加快启动速度。在可能的情况下对大纹理进行压缩。
  11. 避免实时全局光照。
  12. 在接近几何体或绘制调用限制时禁用阴影。
  13. 注意像素光的数量(不超过 2 个)和渲染比例(不超过 1.2),以避免过度的 GPU 负载。
  14. 限制着色器通道的数量,避免性能瓶颈(不超过 2 个)。
  15. 在处理大文件下载时,谨慎使用 Unity 的 WWW 功能。对于非常小的文件,使用该功能是可以接受的。
  16. 对于具有语音聊天的 Android 应用程序,请使用 Microphone API 以避免与 Parties 相关的问题。
  17. 对于大型场景同屏三角面数不超过 50w 面