Unity 的优化技巧

Unity 是一种游戏引擎,不仅在独立开发者中很受欢迎,而且在大公司中也很受欢迎。

它具有用户友好的界面、强大的渲染管道、易于使用的组件系统,最后,它支持大量的平台。

但有了易于使用的界面,就更容易使游戏变得过于复杂(例如 放置 大量不必要的对象等),因此 优化 非常重要在整个开发过程中牢记于心。

以下是针对 3 个主要类别(渲染脚本、音频)的重要提示,可帮助您提高游戏性能:

渲染

技巧 1:保持带有渲染器组件的对象不缩放

未缩放的对象是那些比例为 (1, 1, 1) 的对象。在这种情况下,Unity 不必进行额外的计算来重新缩放每个帧中的对象。

示例: 假设您的房屋模型对于您的水平来说太大或太小。自然的做法是像这样缩放它:

建筑调整大小

大多数情况下,可以在“场景”视图中缩放对象,但如果您计划拥有该对象的大量重复实例,最好在“导入设置”中更改比例。

您需要做的第一件事是缩放模型,直到它适合您的需求(例如,上面的建筑物从 (1, 1, 1) 缩放到 (0.49482, 0.49482, 0.49482)),然后在项目中选择模型视图并在导入设置中记下比例因子(通常为 1 或 0.1)。

设置新值,该值应等于默认比例因子乘以新比例(在我的例子中为 1 x 0.49482 = 0.49482),然后点击“应用”。现在返回到场景视图中的模型并将比例设置回 (1, 1, 1)。

Unity 3D 比例因子设置

现在,对象可以按照您需要的方式缩放,同时保留默认的 (1, 1, 1) 比例。

此技巧对于使用 SkinnedMeshRenderer 的动画对象尤其重要,因为该组件的渲染成本更高,并且比例为 (1, 1, 1) 可以简化渲染过程。

提示 2:使用尽可能少的灯光

Unity 中有 3 种类型的光源(定向光、点光源和聚光灯)。就性能而言,定向光的渲染成本最低,然后是点光,最后是聚光灯。

一般来说,您不希望每个场景有超过 1 个定向光,而对于聚光灯和点光源,请尝试尽可能少(或根本没有)。

就实时阴影而言,虽然它增强了游戏的视觉效果,但它具有高性能开销,因此通常最好禁用它们或将它们烘焙到 lightmapslight 中探针

技巧 3:谨慎使用透明着色器

仅在需要透明的表面上使用透明或粒子着色器(例如栅栏、烟雾粒子等)

具有透明度的对象需要额外的渲染通道,这可能会降低性能,尤其是在资源有限的平台上,例如移动或 Web。

脚本编写

技巧 1:始终缓存组件引用

如果您计划每次更新都访问组件引用,则应始终缓存它们。

例如,检查下面的脚本:

坏的

using UnityEngine;

public class Script1 : MonoBehaviour
{
    float someValue = 0;

    // Update is called once per frame
    void Update()
    {
        someValue = GetComponent<Script2>().someValue2;
    }
}

这里我们有 Script1,它从 Script2 获取变量 "someValue2" 并将其分配给局部变量。

现在,每一帧仅调用一个 GetComponent 不会对性能产生任何影响,但是,您应该养成缓存经常使用的组件的习惯。

有两种方法可以在脚本中缓存组件,或者创建公共变量并在检查器视图中分配它,或者创建私有变量并从 Start 或 Awake 分配它。检查下面的示例:

好的

using UnityEngine;

public class Script1 : MonoBehaviour
{

    float someValue = 0;

    Script2 script2Cached;

    // Use this for initialization
    void Start()
    {
        script2Cached = GetComponent<Script2>();
    }

    // Update is called once per frame
    void Update()
    {
        someValue = script2Cached.someValue2;
    }
}

更好的是,现在可以在每次更新时访问 Script2,而不会产生性能开销。

对内置组件执行相同的操作,例如 BoxCollider、Rigidbody 等(Transform 和 GameObject 除外,这些组件默认已缓存,因此您可以立即访问它们)。

提示 2:谨慎使用 SendMessage

SendMessage 允许您在每个附加 到游戏对象的 MonoBehaviour 上调用特定函数(如果存在)。

例如,当你在游戏中射击武器时,当子弹击中敌人时,你可以快速造成伤害,而不需要使用 GetComponent 和其他额外的东西。

但是,不应过于频繁地调用此方法,因为它的计算量很大。

提示 3:谨慎使用 GameObject.Find 和 GameObject.FindWithTag

GameObject.FindGameObject.FindWithTagGameObject.FindGameObjectsWithTag 可让您快速搜索场景中的对象。这些方法比 GetComponent 慢得多,并且只能在初始化期间使用。

提示 4:避免使用 OnGUI

从历史上看, OnGUI 是在 Unity 中制作 menus 的唯一方法。但从那时起,添加了一个名为 UI Canvas 的替代方案,它在性能方面要好得多,并提供更多功能。

尽管如此,OnGUI 仍然是在 Unity 中制作 UI 的可行方法,如果您绝对需要使用它,请记住 OnGUI 每帧至少调用两次(Update 和 LateUpdate 的两倍),所以不要将其用于 UI 之外的任何计算。

您可以做的一件事是拥有一个单独的脚本,其中仅包含 OnGUI,并在需要时启用/禁用它。

例如:

UIScript.cs

using UnityEngine;

public class UIScript : MonoBehaviour {

    void OnGUI()
    {
        if(GUI.Button(new Rect(5, 5, 125, 25), "Button 1"))
        {
            //Button 1 was pressed, Do Something
        }
        if (GUI.Button(new Rect(140, 5, 125, 25), "Button 2"))
        {
            //Button 2 was pressed, Do Something
        }
    }
}

脚本1.cs

using UnityEngine;

public class Script1 : MonoBehaviour
{

    UIScript uiScript;

    // Use this for initialization
    void Start()
    {
        uiScript = GetComponent<UIScript>();
        uiScript.enabled = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            //toggle UIScript when Tab is pressed
            uiScript.enabled = !uiScript.enabled;
        }
    }
}

UIScript 和 Script1 都附加到同一个 GameObject。Script1 控制何时显示菜单。

当玩家按下 Tab 时,将启用 UIScript,显示按钮。再次按 Tab 键可将其停用,隐藏按钮。

当 UIScript 被停用时,不会调用 OnGUI 方法,这反过来又提高了性能。

技巧 5:使用分析器

Profiler 是识别瓶颈和 fps 下降的最重要工具之一,可以更轻松地找到性能低下的确切原因。

声音的

可以通过确保其导入设置正确来优化音频剪辑。

最佳 音频导入设置 将取决于音频长度、播放频率和目标平台。

推荐文章
如何在Unity中使用更新
Unity 的广告牌生成器
Unity 使用 Profiler 优化您的游戏
提高 Unity 中移动游戏的性能
Unity 音频剪辑导入设置以获得最佳性能
比较 Unity 中的 2D 和 3D 开发环境
游戏设计的基本概念