Unity のパフォーマンスに関する推奨事項

この記事では、Mixed Reality のパフォーマンスに関する推奨事項に基づいていますが、Unity 固有の改善点に焦点を当てています。

私たちは最近、HoloLens 2 アプリの一般的なパフォーマンス、設計、および環境の問題とソリューションをカバーする「品質の基礎」というアプリケーションをリリースしました。 このアプリは、次のコンテンツの優れたビジュアル デモです。

Unity で Mixed Reality アプリのパフォーマンスを最適化する際に最も重要な最初の手順は、Unity に推奨される環境設定を使用していることを確認することです。 この記事には、パフォーマンスの高い Mixed Reality アプリを構築するための最も重要なシーン構成の一部を含むコンテンツが含まれています。 次のセクションでは、これらの推奨設定の一部について説明します。

Unity でプロファイリングする方法

Unity には Unity Profiler が組み込まれており、これは特定のアプリに関する貴重なパフォーマンス分析情報を収集するための優れたリソースです。 プロファイラーはエディター内で実行できますが、これらのメトリックは真の実行時環境を表すものではないため、結果は慎重に使用する必要があります。 オンデバイスで実行中にアプリケーションをリモートでプロファイリングして、最も正確で実用的な分析情報を取得します。

Unity は、以下に関する優れたドキュメントを提供します。

  1. Unity プロファイラーを UWP アプリケーションにリモート接続する方法
  2. Unity Profiler のパフォーマンスの問題を効果的に診断する方法

GPU プロファイリング

Unity プロファイラー

Unity プロファイラーを接続し、GPU プロファイラーを追加した後 (右上隅の「プロファイラーの追加」を参照)、プロファイラーの途中でそれぞれ CPU & GPU に費やされている時間を確認できます。 これにより、デベロッパーは、アプリケーションが CPU バインドまたは GPU バインドであるかどうかをすばやく推定できます。

Unity CPU と GPU

注:

GPU プロファイリングを使用するには、Unity プレイヤー設定でグラフィックス ジョブを無効にする必要があります。 詳細については、Unity の GPU Usage Profiler モジュールを参照してください。

Unity フレーム デバッガー

Unity のフレーム デバッガーも強力で洞察力に富んだツールです。 GPU が各フレームで何をしているかの概要を把握できます。 注意すべき点は、他のレンダリング ターゲットと、HoloLens ではコストがかかるため、それらの間でコピーする blit コマンドです。 理想的には、HoloLens ではオフスクリーン レンダー ターゲットを使用しないでください。 これらは、避けるべき高価なレンダリング機能 (MSAA、HDR、ブルームなどの全画面効果など) を有効にする場合に追加されます。

HoloLens フレーム レートのオーバーレイ

Device Portal の [システム パフォーマンス ] ページには、デバイスの CPU および GPU パフォーマンスの概要が十分にあります。 ヘッドセットの表示フレーム レート カウンターとヘッドセットの表示フレーム レート グラフを有効にすることができます。 これらのオプションでは、デバイスで実行中のアプリケーションに関するフィードバックを即座に取得できる FPS カウンターとグラフがそれぞれ有効になります。

PIX

PIX は、Unity アプリケーションのプロファイリングにも使用できます。 PIX for HoloLens 2 の使用方法とインストール方法に関する詳細な手順もあります。 開発ビルドでは、Unity のフレーム デバッガーに表示されるのと同じスコープが PIX にも表示され、より詳細に検査およびプロファイリングできます。

注:

Unity には、XRSettings.renderViewportScale プロパティを使用して、実行時にアプリケーションのレンダー ターゲット解像度を簡単に変更する機能が用意されています。 デバイス上に表示される最終的な画像の解像度は固定です。 プラットフォームは、ディスプレイにレンダリングするための高解像度の画像を構築するために、低解像度の出力をサンプリングします。

UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;

CPU パフォーマンスに関する推奨事項

以下のコンテンツでは、特に Unity & C# 開発を対象とした、より詳細なパフォーマンス プラクティスについて説明します。

キャッシュ参照

GetComponent<T>() や Camera.main などの関数を繰り返す呼び出しは、ポインターを格納するためのメモリ コストに比べてコストが高くなるため、初期化時にすべての関連コンポーネントと GameObjects への参照をキャッシュすることをお勧めします。 Camera.main は、下で FindGameObjectsWithTag() を使用するだけです。これにより、 "MainCamera" タグを持つカメラ オブジェクトをシーン グラフで高コストに検索します。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

注:

避ける GetComponent(string)
GetComponent() を使用する場合、いくつかの異なるオーバーロードがあります。 常に型ベースの実装を使用し、文字列ベースの検索オーバーロードを使用しないことが重要です。 シーン内の文字列による検索は、タイプで検索するよりもコストがかかります。
(良好)コンポーネント GetComponent(Type type)
(良好)T GetComponent<T>()
(悪い)コンポーネント GetComponent(string)>

負荷のかかる操作を回避する

  1. LINQ を使用しない

    LINQ はクリーンで読み書きが簡単ですが、一般に、手動でアルゴリズムを記述した場合よりも多くの計算とメモリを必要とします。

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. 一般的な Unity API

    特定の Unity API は便利ではありますが、実行にコストがかかる場合があります。 これらのほとんどは、シーン グラフ全体で一致するゲームオブジェクトのリストを検索する必要があります。 通常、これらの操作は、参照をキャッシュするか、実行時に参照を追跡する GameObjects のマネージャー コンポーネントを実装することで回避できます。

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

注:

SendMessage() と BroadcastMessage() は絶対に削除する必要があります。 これらの関数は、直接関数呼び出しよりも 1000 倍低速になる場合があります。

  1. ボクシングに注意

    ボックス化 は、C# 言語とランタイムの主要な概念です。 これは、 char、 int、 bool などの値型の変数を参照型の変数にラップするプロセスです。 値型が "ボックス化" された変数は、 System.Objectにラップされ、マネージ ヒープに格納されます。 メモリは割り当てられ、最終的に破棄されると、ガベージ コレクターによって処理されなければなりません。 これらの割り当てと解放にはパフォーマンス コストが発生しますが、多くの場合、不要であるか、より安価な代替手段に簡単に置き換えることができます。

    ボックス化を避けるには、数値型と構造体 ( Nullable<T>を含む) を格納する変数、フィールド、プロパティが、object を使用するのではなく、 int、 float? 、 MyStruct などの特定の型として型指定するようにしてください。 これらのオブジェクトをリストに入れる場合は、List<object> や ArrayList ではなく、List<int> などの厳密に型指定されたリストを使用してください。

    C 言語でのボックス化の例#

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

繰り返しコード パス

1 秒あたりやフレームあたり何度も実行される Unity コールバック関数 (Update など) を繰り返す場合は、慎重に記述する必要があります。 ここでのコストのかかる操作は、パフォーマンスに大きくて一貫した影響を与えます。

  1. 空のコールバック関数

    以下のコードをアプリケーションに残すのは無害に思えるかもしれませんが、特にすべての Unity スクリプトは Update メソッドを使用して自動初期化されるため、これらの空のコールバックはコストが高くなる可能性があります。 Unity は、アンマネージド コードとマネージド コードの境界、UnityEngine コードとアプリケーション コードの間を行ったり来たりします。 このブリッジを介してコンテキストを切り替える場合、実行するものがない場合でもかなりコストがかかります。 これは、アプリに 100 個ものゲームオブジェクトがあり、そのコンポーネントに空の繰り返し Unity コールバックがある場合に特に問題になります。

    void Update()
    {
    }
    

注:

Update() は、このパフォーマンスの問題の最も一般的な原因ですが、FixedUpdate()、LateUpdate()、OnPostRender"、OnPreRender()、OnRenderImage() など、その他の Unity コールバックの繰り返しは、さらに悪化しないにしても、同じくらい悪い可能性があります。

  1. フレームごとに 1 回実行することを優先する操作

    次の Unity API は、多くのホログラフィック アプリでの一般的な操作です。 常に可能であるとは限りませんが、通常、これらの関数からの結果は 1 回計算され、結果は特定のフレームのアプリケーション全体で再利用されます。

    1. 専用のシングルトン クラスまたはサービスを用意して、シーンへの視線レイキャストを処理し、各コンポーネントで同一のレイキャスト操作を繰り返すのではなく、他のすべてのシーン コンポーネントでこの結果を再利用することをお勧めします。 一部のアプリケーションでは、異なるオリジンからのレイキャストや異なる LayerMask に対してレイキャストが必要になる場合があります。
        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    
    1. Start() や Awake() で参照をキャッシュすることで、Update() のような Unity コールバックの繰り返しでの GetComponent() 操作を避けてください
        UnityEngine.Object.GetComponent()
    
    1. 可能であれば、初期化時にすべてのオブジェクトをインスタンス化し、 オブジェクト プーリング を使用して、アプリケーションの実行中は GameObjects をリサイクルし、再利用することをお勧めします
        UnityEngine.Object.Instantiate()
    
  2. インターフェイスと仮想構造を避ける

    インターフェイスと直接オブジェクトを使用して関数呼び出しを行ったり、仮想関数を呼び出したりする場合、多くの場合、直接構造または直接関数呼び出しを使用するよりもはるかにコストがかかる場合があります。 仮想関数またはインターフェイスが不要な場合は、削除する必要があります。 ただし、これらのアプローチを使用することで開発の共同作業、コードの可読性、コードの保守性が簡素化されるのであれば、これらのアプローチのパフォーマンスへの影響はトレードオフする価値があります。

    一般に、このメンバーを上書きする必要がある明確な予想がない限り、フィールドと関数を仮想としてマークしないことをお勧めします。 フレームごとに何度も呼び出される、または UpdateUI() メソッドのようにフレームごとに 1 回呼び出される高頻度のコード パスに特に注意する必要があります。

  3. 構造体を値で渡さないようにする

    クラスとは異なり、構造体は値型であり、関数に直接渡されると、その内容は新しく作成されたインスタンスにコピーされます。 このコピーでは、CPU コストが追加され、スタック上のメモリも増加します。 小さな構造体の場合、影響は最小限であるため、許容範囲内です。 ただし、フレームごとに繰り返し呼び出される関数と大きな構造体を受け取る関数については、可能であれば、関数定義を参照で渡すように変更します。 詳しくはこちらをご覧ください

その他

  1. 物理学

    1. 一般的に、物理学を改善する最も簡単な方法は、物理学に費やす時間、または 1 秒あたりの反復回数を制限することです。 これにより、シミュレーションの精度が低下します。 UnityのTimeManagerを参照してください。

    2. Unity のコライダーの種類によって、パフォーマンス特性が大きく異なります。 次の順序は、最もパフォーマンスの高いコライダーから最もパフォーマンスの低いコライダーを左から右に一覧表示しています。 メッシュ コライダーを避けることが重要です。メッシュ コライダーはプリミティブ コライダーよりもはるかに高価です。

    Sphere < Capsule < Box <<< メッシュ (凸型) < メッシュ (非凸型)

  2. アニメーション

    アニメーター コンポーネントを無効にして、アイドル状態のアニメーションを無効にします (ゲーム オブジェクトを無効にしても、同じ効果はありません)。 アニメーターが同じものに値を設定するループ内にいるようなデザイン パターンは避けてください。 この手法にはかなりのオーバーヘッドがかかり、アプリケーションには影響しません。 詳細については、こちらを参照してください。

  3. 複雑なアルゴリズム

    アプリケーションが逆運動学、パス検索などの複雑なアルゴリズムを使用している場合は、より簡単なアプローチを見つけるか、パフォーマンスに関連する設定を調整してください。

CPU から GPU に対するパフォーマンスに関する推奨事項

一般に、CPU から GPU へのパフォーマンスは、グラフィックス カードに送信される描画呼び出しによって決まります。 パフォーマンスを向上させるには、描画呼び出しを戦略的に a) 削減 するか、b) 最適な結果を得るために 再構成 する必要があります。 描画呼び出し自体はリソースを消費するため、描画呼び出しを減らすと、全体的な作業が少なくなります。 さらに、描画呼び出しの間の状態変更には、グラフィックス ドライバーでコストのかかる検証と変換手順が必要になるため、アプリケーションの描画呼び出しを再構成して状態の変更 (つまり、異なるマテリアルなど) を制限すると、パフォーマンスを向上させることができます。

Unity には、概要を提供し、プラットフォームでの描画呼び出しのバッチ処理について詳しく説明した素晴らしい記事があります。

シングル パスインスタンス レンダリング

Unity のシングル パスインスタンスレンダリングでは、各目の描画呼び出しを 1 つのインスタンス化された描画呼び出しに減らすことができます。 2 つの描画呼び出し間のキャッシュの一貫性により、GPU のパフォーマンスもある程度向上します。

Unity プロジェクトでこの機能を有効にするには

  1. [OpenXR の設定] を開きます ([編集]>[プロジェクト設定]>[XR プラグイン管理]>OpenXR に移動します)。
  2. レンダリング モード(Render Mode) ドロップダウン メニューからシングル パスインスタンス化 (Single Pass Instanced) を選択します。

このレンダリング アプローチの詳細については、Unity の次の記事を参照してください。

注:

シングル パス インスタンス レンダリングに関する一般的な問題の 1 つは、開発者がインスタンス化用に記述されていない既存のカスタム シェーダーを既に持っている場合に発生します。 この機能を有効にすると、開発者は一部のゲーム オブジェクトが片目でのみレンダリングされることに気付く場合があります。 これは、関連付けられているカスタム シェーダーにインスタンス化に適したプロパティがないためです。

静的バッチ処理

Unity では、GPU への描画呼び出しを減らすために、多くの静的オブジェクトをバッチ処理できます。 静的バッチ処理は、1) 同じマテリアルを共有し、2) すべて静的 (Unity でオブジェクトを選択し、インスペクターの右上のチェックボックスを選択する) の Unity のほとんどのレンダラー オブジェクトで機能します。 静的とマークされたゲームオブジェクトは、アプリケーションのランタイム全体を通じて移動することはできません。 そのため、事実上すべてのオブジェクトの配置、移動、拡大縮小などを行う必要がある HoloLens では、静的バッチ処理を適用するのが難しい場合があります。イマーシブ ヘッドセットの場合、静的バッチ処理によって描画呼び出しが大幅に削減され、結果としてパフォーマンスが向上します。

詳細については、「Unity の描画呼び出しバッチ処理」の「静的バッチ処理」を参照してください。

動的バッチ処理

HoloLens 開発では オブジェクトを静的 としてマークすることは問題があるため、動的なバッチ処理は、この不足している機能を補うための優れたツールになる可能性があります。 また、イマーシブ ヘッドセットでも役立ちます。 ただし、Unity の動的バッチ処理は、ゲームオブジェクトが a) 同じマテリアルを共有し、b) 他の条件の長いリストを満たす必要があるため、有効にするのが難しい場合があります。

完全な一覧については、「Unity の描画呼び出しバッチ処理」で動的バッチ処理を参照してください。 ほとんどの場合、GameObjects は動的にバッチ処理することが無効になります。これは、関連付けられたメッシュ データは 300 個以下の頂点にできるためです。

その他の手法

バッチ処理は、複数のゲームオブジェクトが同じマテリアルを共有できる場合にのみ発生します。 通常これは、ゲーム オブジェクトがそれぞれのマテリアルに固有のテクスチャを持つ必要があるためブロックされます。 テクスチャを 1 つの大きなテクスチャに結合することは一般的です。これは、 テクスチャ アトラスと呼ばれる方法です。

さらに、可能かつ妥当であれば、複数のメッシュを 1 つのゲームオブジェクトに結合することをお勧めします。 Unity の各レンダラーには、1 つのレンダラーの下で結合されたメッシュを送信することに関連する描画呼び出しがあります。

注:

実行時に Renderer.material のプロパティを変更すると、マテリアルのコピーが作成され、バッチ処理が中断される可能性があります。 Renderer.sharedMaterial を使用して、ゲームオブジェクト間で共有されるマテリアル プロパティを変更します。

GPU パフォーマンスに関する推奨事項

帯域幅とフィル レート

GPU でフレームをレンダリングする場合、アプリケーションはメモリ帯域幅またはフィル レートのいずれかによって制約されます。

  • メモリ帯域幅は 、GPU がメモリから実行できる読み取りと書き込みの速度です
    • Unity では、[Edit>Project Settings]>Quality Settings でテクスチャ品質を変更します。
  • フィル レート とは、GPU が 1 秒あたりに描画できるピクセルのことです。

深度バッファー共有の最適化

ホログラムの安定性を最適化するために、深度バッファー共有を有効にすることをお勧めします。 この設定で深度ベースの後期再投影を有効にする場合は、24 ビット深度フォーマットではなく 16 ビット深度フォーマットを選択することをお勧めします。 16 ビット深度バッファーを使用すると、深度バッファー トラフィックに伴う帯域幅 (ひいては電力) が大幅に削減されます。 これは、電力削減とパフォーマンスの両方で大幅に向上する可能性があります。 ただし、 16 ビット深度フォーマットを使用すると、悪影響が 2 つ考えられます。

Zファイティング

深度範囲の忠実度が低いため、 z ファイティング は 24 ビットよりも 16 ビットで発生する可能性が高くなります。 これらのアーティファクトを回避するには、Unity カメラの近距離/遠距離のクリップ プレーンを変更して、精度が低いことを考慮します。 HoloLens ベースのアプリケーションの場合、Unity の既定の 1,000 m の代わりに 50 m の遠いクリップ平面を使用すると、一般的に Z ファイティングを排除できます。

無効なステンシル バッファー

Unity が 16 ビット深度のレンダー テクスチャを作成する場合、ステンシル バッファーは作成されません。 Unity ドキュメントで説明されているように、24 ビットの深度形式を選択すると、24 ビットの Z バッファーと 8 ビットのステンシル バッファーが作成されます (デバイス (HoloLens など) で 32 ビットを適用できる場合は、一般的にそうなります)。

全画面表示効果を避ける

全画面表示で動作する手法は、その桁違いが 1 フレームあたり数百万回の操作であるため、高価になる可能性があります。 アンチエイリアス、ブルームなどの ポストプロセッシング効果 を避けることをお勧めします。

最適な照明設定

Unity のリアルタイム グローバル イルミネーションは、優れた視覚的結果を提供できますが、コストのかかる照明計算を伴います。 [Window>Rendering]>[Lighting Settings] を使用して、すべてのUnityシーン ファイルのリアルタイム グローバル イルミネーションを無効にすることをお勧めします> [リアルタイム グローバル イルミネーション] の選択を解除します。

さらに、シャドウ キャストは高コストの GPU パスを Unity シーンに追加するため、すべてのシャドウ キャストを無効にすることをお勧めします。 影はライトごとに無効にできますが、品質設定を使用して全体的に制御することもできます。

編集>[プロジェクト設定] をクリックし、[品質] カテゴリを選択し> UWP プラットフォームの [低品質] を選択します。 また、 Shadows プロパティを Disable Shadows に設定することもできます。

Unity のモデルにはベイク ライティングを使用することをお勧めします。

ポリゴン数を減らす

ポリゴン数は、次のいずれかの

  1. シーンからのオブジェクトの削除
  2. アセットのデシメーション (特定のメッシュのポリゴンの数を減らす)
  3. 詳細 レベル (LOD) システムを アプリケーションに実装すると、同じジオメトリの下ポリゴン バージョンを使用して遠くにあるオブジェクトをレンダリングできます

Unity のシェーダーを理解する

シェーダーのパフォーマンスを比較する簡単な概算は、実行時にそれぞれの操作が実行される平均数を特定することです。 これは Unity で簡単に行うことができます。

  1. シェーダー アセットを選択するかマテリアルを選択し、インスペクター ウィンドウの右上隅で を選択します。 歯車アイコンを選択し、 次に [シェーダーの選択] を選択します。

    Unity でシェーダーを選択する

  2. シェーダー アセットが選択されている状態で、インスペクター ウィンドウの下にある [コードをコンパイルして表示] ボタンを選択します。

    Unity でシェーダー コードをコンパイルする

  3. コンパイル後、頂点シェーダーとピクセル シェーダーの両方に対する異なる操作の数を含む結果の統計セクションを探します (注: ピクセル シェーダーは、多くの場合、フラグメント シェーダーとも呼ばれます)。

    Unity Standard シェーダー操作

ピクセル シェーダーを最適化する

上記の方法でコンパイルされた統計結果を見ると、 フラグメント シェーダー は通常、 頂点シェーダーよりも平均して多くの操作を実行します。 フラグメント シェーダー (ピクセル シェーダーとも呼ばれる) は、画面出力のピクセル単位で実行されますが、頂点シェーダーは、画面に描画されるすべてのメッシュの頂点単位でのみ実行されます。

したがって、すべての照明計算のために、フラグメント シェーダーは頂点シェーダーよりも多くの命令を持っているだけでなく、フラグメント シェーダーはほとんどの場合、より大きなデータセットで実行されます。 たとえば、画面出力が 2k × 2k の画像の場合、フラグメント シェーダーは 2,000*2,000 = 4,000,000 回実行できます。 2 つの目をレンダリングする場合、2 つの画面があるため、この数値は 2 倍になります。 Mixed Reality アプリケーションに複数のパス、全画面表示の後処理効果、または同じピクセルへの複数のメッシュのレンダリングがある場合、この数は劇的に増加します。

したがって、フラグメント シェーダーの操作の数を減らすと、一般に、頂点シェーダーの最適化よりもはるかに大きなパフォーマンス向上が得られます。

Unity Standard シェーダーの代替手段

物理ベース レンダリング (PBR) や別の高品質シェーダーを使用する代わりに、よりパフォーマンスで安価なシェーダーの使用を検討してください。 Mixed Reality ツールキット には、Mixed Reality プロジェクト用に最適化された MRTK 標準シェーダーが用意されています。

Unity では、Unity Standard シェーダーと比較して高速な、アンライティング、頂点ライティング、ディフューズなどの簡略化されたシェーダー オプションも用意されています。 詳細については、「 組み込みシェーダーの使用方法とパフォーマンス」を参照してください。

シェーダーのプリロード

シェーダーのプリロードやその他のテクニックを使用して、シェーダーの読み込み時間を最適化します。 特に、シェーダーのプリロードは、ランタイム シェーダーのコンパイルに起因する問題が発生しないことを意味します。

オーバードローの制限

Unity では、シーン ビューの左上隅にある描画モード メニューを切り替えて [オーバードロー] を選択することで、シーンのオーバードローを表示できます。

一般に、オブジェクトを GPU に送信する前に前もってカリングすることで、オーバードローを軽減できます。 Unity では、エンジンにオクルージョン カリングを実装する方法について詳しく説明しています。

メモリの推奨事項

過剰なメモリ割り当て & 割り当て解除操作は、ホログラフィック アプリケーションに悪影響を及ぼし、その結果、パフォーマンスが悪化したり、フレームがフリーズしたり、その他の有害な動作が発生する可能性があります。 メモリ管理はガベージ コレクターによって制御されるため、Unity で開発する場合はメモリに関する考慮事項を理解することが特に重要です。

ガーベジ コレクション

実行中にスコープ外になったオブジェクトを分析するために GC がアクティブになり、それらのメモリを再利用できるようにする必要がある場合、Holographic アプリはガベージ コレクター (GC) の処理演算時間を失います。 定数の割り当てと割り当て解除では、一般にガベージ コレクターの実行頻度が高くなるため、パフォーマンスとユーザー エクスペリエンスが低下します。

過剰なガベージ コレクションにつながる最も一般的な方法の 1 つは、Unity 開発でコンポーネントとクラスへの参照をキャッシュしないことです。 参照はすべて Start() または Awake() 中にキャプチャし、Update() や LateUpdate() などの後の関数で再利用する必要があります。

その他のクイック ヒント:

  • 実行時に複雑な文字列を作成するには、 StringBuilder C# クラスを使用します。
  • Debug.Log() の呼び出しは、アプリのすべてのビルド バージョンで引き続き実行されるため、不要になった場合は削除します
  • 一般的にホログラフィック アプリに大量のメモリが必要な場合は、読み込み中や画面を表示するときなど、読み込みフェーズで System.GC.Collect() を呼び出すことを検討してください。

オブジェクト プーリング

オブジェクト プーリングは、継続的なオブジェクト割り当てと割り当て解除のコストを削減するための一般的な手法です。 これは、同じオブジェクトの大きなプールを割り当て、時間の経過と共にオブジェクトを絶えずスポーンおよび破棄する代わりに、このプールから非アクティブで使用可能なインスタンスを再利用することによって行われます。 オブジェクト プールは、アプリケーション中に有効期間が可変の再利用可能なコンポーネントに適しています。

起動時のパフォーマンス

小さなシーンでアプリを起動した後、 SceneManager.LoadSceneAsync を使用してシーンの残りの部分を読み込むことを検討してください。 これにより、アプリはできるだけ速く対話型状態に到達できます。 新しいシーンがアクティブ化されている間に大きな CPU スパイクが発生し、レンダリングされたコンテンツが途切れたりヒッチしたりする可能性があります。 これを回避する 1 つの方法は、読み込み中のシーンで AsyncOperation.allowSceneActivation プロパティを "false" に設定し、シーンが読み込まれるのを待ってから画面を黒にクリアしてから "true" に戻してシーンのアクティブ化を完了することです。

スタートアップ シーンの読み込み中は、ホログラフィックのスプラッシュ画面がユーザーに表示されることに注意してください。