パフォーマンス — MRTK2

作業の開始

パフォーマンスを合理的に説明する最も簡単な方法は、フレームレート、つまりアプリケーションが 1 秒あたりにイメージを何回レンダリングできる回数を使用することです。 ターゲットにしているプラットフォーム (Windows Mixed RealityOculus など) の説明に従って、ターゲット フレームレートに合わせることが重要です。 たとえば HoloLens では、ターゲット フレームレートは 60 FPS です。 フレームレートの低いアプリケーションでは、ホログラムの安定性、ワールド トラッキング、ハンド トラッキングなどが悪くなるなど、ユーザー エクスペリエンスが低下する可能性があります。 開発者が品質フレームレートを追跡して達成できるように、Mixed Reality Toolkit にはさまざまなツールとスクリプトが用意されています。

ビジュアル プロファイラー

開発の有効期間にわたってパフォーマンスを継続的に追跡するには、アプリケーションのデバッグ & 実行中に常にフレームレートビジュアルを表示することを強くお勧めします。 Mixed Reality Toolkit には、アプリケーション ビューでの現在の FPS とメモリ使用量に関するリアルタイム情報を提供する Visual Profiler 診断ツールが用意されています。 Visual Profiler は、MRTK Profiles Inspector診断システム設定を介して構成できます。

さらに、特に重要なのは Visual Profiler を使用して、Unity エディターやエミュレーターで実行しているときのフレームレートでなく、デバイスで実行しているときのフレームレートを追跡することです。 最も正確なパフォーマンスの結果は、リリース構成ビルドを使用したデバイスで実行中に示されます。

Note

Windows Mixed Reality用にビルドする場合は、MASTER 構成ビルドを使用してデプロイします。

Visual Profiler インターフェイス

最適化ウィンドウ

MRTK 最適化ウィンドウには、Mixed Reality 開発者が最適なパフォーマンスの結果を得るために環境を設定し、シーン & 資産の潜在的なボトルネックを特定するのに役立つ情報と自動化ツールが用意されています。 Unity における特定の重要構成は、Mixed Reality プロジェクトで極めて最良の結果を実現するのに役立ちます。

一般に、これらの設定に関わるレンダリング構成は、Mixed Reality に理想的です。 Mixed Reality アプリケーションが従来の 3D グラフィックス開発と比べてユニークなのは、シーン全体に対してレンダリングする 2 つの画面 (つまり、2 つの目) があるという点です。

以下で参照する推奨設定は、Unity プロジェクトで MRTK 最適化ウィンドウを利用することで自動構成できます。

MRTK のウィンドウ設定の最適化

Unity Profiler

Unity Profiler は、アプリケーション パフォーマンスの詳細をフレーム単位で調査するのに便利なツールです。

CPU で費やされた時間

Unity Profiler Graph の例

快適なフレーム レート (通常は 60 フレーム/秒) を維持するには、アプリケーションで最大フレーム時間 16.6 ミリ秒の CPU 時間を達成する必要があります。 MRTK 機能のコストを特定するために、Microsoft Mixed Reality Toolkit には、内部ループ (フレームごと) コード パスのマーカーが含まれています。 これらのマーカーは、使用されている特定の機能がわかるように、以下の形式を使用します。

[MRTK] className.methodName

Note

メソッド名の後に、追加のデータがあります。 これは、条件付きで実行され、高コストになる可能性があり、アプリケーション コードをわずかに変更することで回避される可能性がある機能を見つけ出すために使用されます。

Unity Profiler 階層の例

この例では、階層は拡張されて、WindowsMixedRealityArticulatedHand クラスの UpdateHandData メソッドが、フレームの分析中に 0.44 ミリ秒の CPU 時間を消費していることを示しています。 このデータを使用すると、パフォーマンスの問題がアプリケーション コードに関連しているのか、システム内の他の場所から発生したのかを調べることができます。

強くお勧めするのは、開発者がアプリケーション コードを、同様の方法で装備することです。 アプリケーション コード インストルメンテーションの主な重点領域がイベント ハンドラー内にあるのは、これらのメソッドはイベントが発生すると MRTK 更新ループに課金されるからです。 MRTK 更新ループ内のフレーム時間が多い場合は、イベント ハンドラー メソッド内の高コストのコードを示している可能性があります。

単一パス インスタンス化レンダリング

Unity における XR の既定のレンダリング構成はマルチパスです。 この設定は Unity に、レンダリング パイプライン全体を 2 回、1 つの眼に 1 回ずつ実行するよう指示します。 これを最適化するには、単一パス インスタンス化レンダリングを代わりに選択します。 この構成ではレンダー ターゲット配列を利用して、適切なレンダー ターゲット にインスタンス化する単一描画呼び出しを、それぞれの眼で実行できるようにします。 さらに、このモードではすべてのレンダリングをレンダリング パイプラインの 1 回の実行で行うことができます。 したがって、Mixed Reality アプリケーションのレンダリング パスとして [Single Pass Instanced レンダリング] を選択すると、 CPU & GPU の両方で大幅な時間を節約 でき、推奨されるレンダリング構成になります。

ただし、各メッシュの単一描画呼び出しをそれぞれの眼に発行するためには、すべてのシェーダーで GPU インスタンス化がサポートされている必要があります。 インスタンス化によって、GPU は両方の眼で描画呼び出しを多重化できます。 Unity の組み込みシェーダーおよび MRTK 標準シェーダーは、必要なインスタンス化指示を既定でシェーダーコードに含んでいます。 Unity 用にカスタム シェーダーを記述している場合は、単一パス インスタンス化レンダリングをサポートするためにこれらのシェーダーの更新が必要になる場合があります。

カスタム シェーダーのコードの例

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;

    UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;

    UNITY_VERTEX_OUTPUT_STEREO //Insert
};

v2f vert (appdata v)
{
    v2f o;

    UNITY_SETUP_INSTANCE_ID(v); //Insert
    UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert

    o.vertex = UnityObjectToClipPos(v.vertex);

    o.uv = v.uv;

    return o;
}

品質設定

Unity には、プラットフォーム エンドポイントごとにレンダリングの品質を制御するプリセットが用意されています。 これらのプリセットは、シャドウ、アンチエイリアシング、グローバル照明など、どのようなグラフィカル機能を有効にできるかを制御します。 これらの設定を小さくして、レンダリング中に実行される計算の数を最適化することをお勧めします。

手順 1: "低品質" レベルの設定を使用するように Mixed Reality Unity プロジェクトを更新する
[編集]>[プロジェクト設定] を選択して [品質] カテゴリを選択 > [UWP プラットフォーム] で [低品質] を選択

手順 2: すべての Unity シーン ファイルで、リアルタイム グローバル照明を無効にする
[ウィンドウ]>[レンダリング]>[照明の設定]>[リアルタイムグローバル照明] をオフにする

深度バッファーの共有 (HoloLens)

Windows Mixed Reality プラットフォーム向けに、特定の HoloLens で開発を行う場合、[XR 設定][深度バッファーの共有] を有効にすると、ホログラムの安定化に役立ちます。 ただし、特に 24 ビットの深度フォーマットを使用する場合は、深度バッファーの処理によってパフォーマンス コストがかかる可能性があります。 そのため、深度バッファーを 16 ビット精度に構成することを強くお勧めします。

それより低いビット形式が原因で z ファイティングが発生した場合は、すべてのカメラの遠いクリップ平面がアプリケーションで使用可能な最小値に設定されていることを確認します。 Unity では、既定で 1000 m の遠いクリップ平面が設定されます。 HoloLens では、50 m の遠いクリップ平面が一般にはほとんどのアプリケーション シナリオで十分です。

Note

"16 ビットの深度フォーマット" を使用する場合、この設定では Unity はステンシル バッファーを作成しないため、ステンシル バッファーを必要とする効果は機能しません。 "24 ビットの深度フォーマット" を選択した場合、エンドポイントのグラフィックス プラットフォームが対応する場合は、通常、8 ビットのステンシル バッファーが作成されます。

ステンシル バッファーを必要とするマスク コンポーネントを使用する場合は、RectMask2D を代わりに使用することを検討してください。これはステンシル バッファーを必要としないため、"16 ビットの深度フォーマット" と組み合わせて使用できます。

Note

シーン内のどのオブジェクトが深度バッファーに視覚的に書き込まれないかをすばやく調べるには、MRTK 構成プロファイルの [エディターの設定] の下にある [レンダー深度バッファー] ユーティリティを使用できます。

メッシュ データの最適化

[メッシュ データの最適化] の設定では、アプリケーション内で使用されていない頂点属性を削除しようとします。 この設定はこれを行うために、ビルド内のすべてのメッシュ上のすべてのマテリアルですべてのシェーダー パスを実行します。 これによってゲームのデータ サイズが削減され、実行時のパフォーマンスが向上しますが、ビルド時間が大幅に長くなる可能性があります。

開発中はこの設定を無効にし、"マスター" ビルドの作成時に再び有効にすることをお勧めします。 この設定は、[編集]>[プロジェクト設定]>[プレーヤー]>[その他の設定]>[メッシュ データの最適化] の下にあります。

一般的な推奨事項

パフォーマンスとはあいまいなもので、Mixed Reality の開発者にとって常に変化する課題です。そして、パフォーマンスを合理的に説明する知識の範囲は膨大です。 アプリケーションのパフォーマンスにアプローチする方法を理解するための一般的な推奨事項があります。

CPU または GPU で実行される部分にまでアプリケーションの実行を簡略化し、アプリがどちらのコンポーネントに制約されているのかを特定することは有用です。 ボトルネックは両方の処理ユニットに、また、いくつかの固有のシナリオにまたがっている可能性があり、慎重に調査する必要があります。 しかし、まずは、アプリケーションの実行時間の大半を占めている箇所を把握することから始めるとよいでしょう。

GPU による制約

Mixed Reality アプリケーション向けのほとんどのプラットフォームではステレオスコピック レンダリングを利用しているため、"ダブルワイド" 画面をレンダリングするという性質上、GPU に制約されるのが一般的です。 さらに、HoloLens や Oculus Quest などのモバイル Mixed Reality プラットフォームは、モバイル クラスの CPU & GPU 処理能力によって制限されます。

GPU に重点を置くとき、一般にはアプリケーションがすべてのフレームで完了しなければならない 2 つの重要なステージがあります。

  1. 頂点シェーダーを実行する
  2. ピクセル シェーダー (フラグメント シェーダーとも呼ばれる) を実行する

コンピューター グラフィックス & レンダリング パイプラインの複雑な分野に深く掘り下げることなく、各シェーダー ステージは GPU 上で実行され、以下を生成するプログラムです。

  1. 頂点シェーダーがメッシュ頂点を画面空間内の座標に変換する (つまり、コードが頂点ごとに実行される)
  2. ピクセル シェーダーが、特定のピクセルとメッシュ フラグメントに描画する色を計算する (つまり、コードがピクセルごとに実行される)

パフォーマンスのチューニングに関して、通常はピクセル シェーダーでの操作の最適化に重点を置く方が有益です。 アプリケーションによっては、キューブ、つまり 8 つの頂点を描画するだけで済むかもしれません。 ただし、キューブが占有する画面領域は、何百万ピクセルにも達します。 したがって、シェーダー コードでたとえば 10 回の操作を削減する場合、頂点シェーダーよりもピクセル シェーダーで削減した方が、処理量を大幅に節約できます。

これは、 MRTK Standard シェーダー を利用する主な理由の 1 つです。一般に、このシェーダーは、同等の美的な結果を得ながら、Unity Standard シェーダーよりもピクセル & 頂点あたりの命令数が少ないためです。

CPU の最適化 GPU の最適化
アプリ シミュレーション ロジック レンダリング操作
物理計算を簡略化する 照明計算を削減する
アニメーションを簡略化する 描画可能なオブジェクトの数 & ポリゴン数を減らす
ガベージ コレクションを管理する 透過オブジェクトの数を減らす
参照をキャッシュする 後処理/全画面の影響を回避する

描画呼び出しの例

Unity で最もよくある、パフォーマンスを低下させる間違いの 1 つが、実行時に素材を複製することです。 GameObjects が同じ素材を共有したり同じメッシュであったりする場合は、静的バッチ処理動的バッチ処理GPU インスタンス化などの手法を使用して、単一の描画呼び出しに最適化できます。 ただし、開発者がレンダラーの素材のプロパティを実行時に変更した場合、Unity が割り当てられた素材の複製コピーを作成します。

たとえば、100 個のキューブがシーン内にある場合、開発者はそれぞれに一意の色を実行時に割り当てたいと考えるかもしれません。 C# で renderer.material.color にアクセスすることで、Unity がこの特定のレンダラー/GameObject のメモリに新しい素材を作成します。 100 個のキューブのそれぞれに独自の素材が用意されるため、これらをまとめてマージして 1 つの描画呼び出しにすることはできませんが、代わりに CPU から GPU への 100 回の描画呼び出し要求になります。

この障害を克服してキューブごとに一意の色を割り当てるために、開発者は MaterialPropertyBlock を活用する必要があります。

private PropertyBlock m_PropertyBlock ;
private Renderer myRenderer;

private void Start()
{
     myRenderer = GetComponent<Renderer>();
     m_PropertyBlock = new MaterialPropertyBlock();
}

private void ChangeColor()
{
    // Creates a copy of the material once for this renderer
    myRenderer.material.color = Color.red;

    // vs.

    // Retains instancing capability for renderer
    m_PropertyBlock.SetColor("_Color", Color.red);
    myRenderer.SetPropertyBlock(m_PropertyBlock);
}

Unity パフォーマンス ツール

Unity が提供する優れたパフォーマンス ツールは、エディターに組み込まれています。

あるシェーダーと別のシェーダーの間のパフォーマンスの大まかなトレードオフを見積もっている場合は、それぞれのシェーダーをコンパイルし、シェーダー ステージあたりの操作数を評価するとよいでしょう。 これを行うには、シェーダー アセットを選択して [コードをコンパイルして表示] ボタンをクリックします。 これによりすべてのシェーダー バリアントがコンパイルされて、Visual Studio が結果と共に開きます。 注: 作成される統計の結果は、指定されたシェーダーを使用する素材で有効になっている機能に応じて異なる場合があります。 Unity では、現在のプロジェクトで直接使用されているシェーダー バリアントだけがコンパイルされます。

Unity 標準シェーダー統計の例

Unity 標準シェーダー統計 1

MRTK 標準シェーダー統計の例

MRTK 標準シェーダー統計 2

関連項目

Unity

Windows Mixed Reality

Oculus

メッシュ最適化