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 種類のライトがあります (指向性ライト、ポイント ライト、スポットライト)。パフォーマンスの点では、指向性ライトがレンダリングに最も安価で、次にポイント、最後がスポットライトです。

一般に、シーンごとに複数の指向性ライトを使用することは望ましくありません。また、スポット ライトとポイント ライトについては、できるだけ少なくするようにします (またはまったく持たないようにします)。

リアルタイム シャドウに関しては、ゲームのビジュアル面が向上しますが、パフォーマンスの高いオーバーヘッドがあるため、一般的には無効にするか、ライトマップ および ライトにベイクすることをお勧めします。プローブ

ヒント 3: 透明シェーダの使用には注意が必要です

透明にする必要があるサーフェス (フェンス、スモーク パーティクルなど) でのみ、透明シェーダまたはパーティクル シェーダを使用してください。

透明性のあるオブジェクトには追加のレンダリング パスが必要であり、特にモバイルや Web などリソースが限られているプラ​​ットフォームではパフォーマンスが低下する可能性があります。

スクリプト作成

ヒント 1: コンポーネント参照を常にキャッシュする

更新のたびにコンポーネント参照にアクセスする予定がある場合は、常にコンポーネント参照をキャッシュする必要があります。

たとえば、以下のスクリプトを確認してください。

悪い

using UnityEngine;

public class Script1 : MonoBehaviour
{
    float someValue = 0;

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

ここでは、Script2 から変数 "someValue2" を取得し、それをローカル変数に割り当てる Script1 があります。

各フレームで GetComponent を 1 つだけ呼び出してもパフォーマンスには影響しませんが、頻繁に使用されるコンポーネントをキャッシュする習慣を身に付ける必要があります。

スクリプトでコンポーネントをキャッシュするには 2 つの方法があります。パブリック変数を作成してインスペクター ビューで割り当てるか、プライベート変数を作成して 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;
    }
}

さらに、パフォーマンスのオーバーヘッドを発生させずに、Update ごとに Script2 にアクセスできるようになりました。

BoxCollider、Rigidbody などの組み込みコンポーネントに対しても同じことを行います (Transform と GameObject を除く、これらはデフォルトですでにキャッシュされているため、すぐにアクセスできます)。

ヒント 2: SendMessage は注意して使用してください

SendMessage を使用すると、ゲーム オブジェクトに attached されているすべての MonoBehaviour で特定の関数 (存在する場合) を呼び出すことができます。

たとえば、ゲーム内で武器を撃つ場合、GetComponent やその他の余分なものを使用することなく、弾丸が敵に当たるとすぐにダメージを与えることができます。

ただし、このメソッドは非常に大量の計算を行うため、あまり頻繁に呼び出すべきではありません。

ヒント 3: GameObject.Find と GameObject.FindWithTag は注意して使用してください

GameObject.FindGameObject.FindWithTag、および GameObject.FindGameObjectsWithTag を使用すると、シーン内のオブジェクトをすばやく検索できます。これらのメソッドは GetComponent よりもはるかに遅いため、初期化中にのみ使用する必要があります。

ヒント 4: OnGUI の使用を避ける

歴史的には、Unity で menus を作成するには、OnGUI が唯一の方法でした。しかしそれ以来、UI Canvas という代替手段が追加されました。これはパフォーマンスの点ではるかに優れており、より多くの機能を提供します。

それにもかかわらず、OnGUI は依然として Unity で UI を作成する実行可能な方法であり、どうしてもそれを使用する必要がある場合は、OnGUI がフレームごとに少なくとも 2 回 (Update と LateUpdate の 2 倍) 呼び出されることに注意してください。 UI 以外の計算にも使用します。

できることの 1 つは、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 の低下を特定する際に最も重要なツールの 1 つであり、パフォーマンス低下の正確な原因を簡単に見つけることができます。

オーディオ

オーディオ クリップは、インポート設定が正しいことを確認することで最適化できます。

最適な オーディオ インポート設定 は、オーディオの長さ、再生頻度、ターゲット プラットフォームによって異なります。

おすすめの記事
Unityでアップデートを利用する方法
Unity 用のビルボード ジェネレーター
Unity プロファイラーを使用してゲームを最適化する
Unity でのモバイル ゲームのパフォーマンスの向上
最高のパフォーマンスを実現する Unity オーディオ クリップのインポート設定
Unity の 2D 開発環境と 3D 開発環境の比較
ゲームデザインの基本概念