MRが楽しい

MRやVRについて学習したことを書き残す

MRTK v2のドキュメントを少しずつ読み解くパフォーマンス その2

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

前回記事の続きです。
bluebirdofoz.hatenablog.com

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200130092628j:plain

推奨事項

複合現実開発者にとって、パフォーマンスは曖昧で常に変化する課題であり、パフォーマンスを合理化するための知識は膨大です。
ただし、アプリケーションのパフォーマンスにアプローチする方法を理解するための推奨事項がいくつかあります。

アプリケーションの実行をCPUまたはGPUで実行される部分に単純化して、アプリがいずれかのコンポーネントにバインドされているかを識別すると効果的です。
慎重に調査する必要があるいくつかの固有のシナリオと処理ユニットの両方に及ぶボトルネックが存在する可能性があります。
初めに、アプリケーションが最も長時間実行されている場所を把握することをお勧めします。

GPUバウンド

Mixed Realityアプリケーションのほとんどのプラットフォームは立体視レンダリングを利用しています。
2倍の幅のレンダリングの性質により、GPUによる制約は非常に一般的です。
更にHoloLensやOculus Questなどのモバイル複合現実プラットフォームはモバイルクラスのCPUとGPUの処理能力に制限されます。

GPUに焦点を当てる場合、通常アプリケーションが全てのフレームを完了するのに必要な2つの重要な段階があります。

1.頂点シェーダーを実行する
2.ピクセルシェーダ(またはフラグメントシェーダ)を実行する。

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

1.頂点シェーダーはメッシュの頂点をスクリーン空間の座標に変換します。つまり、頂点ごとに実行されます。
2.ピクセルシェーダーは特定のピクセルとメッシュフラグメントに対して描画する色を計算します。つまり、ピクセルごとに実行されます。

パフォーマンスチューニングに関しては、通常ピクセルシェーダーの最適化に焦点を当てることがより有益です。
アプリケーションで必要なのは例えば8つの頂点を持つキューブを描画することです。
ただし、キューブが占める画面スペースは、おそらく数百万ピクセルとなります。
したがって、頂点シェーダーよりもピクセルシェーダーを削減した場合に、大幅に処理を軽減できます。

これは、MRTK Standard シェーダーを活用する主な理由の1つです。
このシェーダーは、通常 Unity Standard シェーダーよりもピクセルおよび頂点あたりの命令数がはるかに少なく、同等の描画結果を実現するためです。


CPU最適化GPU最適化
シミュレーションロジックレンダリング処理
物理演算を簡素化する照明の計算を減らす
アニメーションを簡素化するポリゴン数と描画オブジェクトを減らす
ガベージコレクションを管理する透明なオブジェクトを減らす
キャッシュ参照を行う後処理/フルスクリーン効果を避ける

ドローコールインスタンス

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

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

この問題を克服してキューブごとに一意の色を割り当てるには、MaterialPropertyBlock を活用する必要があります。

private MaterialPropertyBlock m_PropertyBlock ;
private Renderer myRenderer;

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

private void ChangeColor()
{
    // 本記述ではマテリアルのコピーを作成してしまいます
    myRenderer.material.color = Color.red;

    // 以下が対処例になります
    // 本記述ではレンダラーのインスタンスを保持します
    m_PropertyBlock.SetColor("_Color", Color.red);
    myRenderer.SetPropertyBlock(m_PropertyBlock);
}

Unityパフォーマンスツール

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

・Unity Profiler
https://docs.unity3d.com/Manual/Profiler.html
・Unity Frame Debugger
https://docs.unity3d.com/Manual/FrameDebugger.html

シェーダー間の大まかなパフォーマンスの差を見積もる場合、各シェーダーをコンパイルしてシェーダーステージごとの操作数を表示すると便利です。
これを行うにはシェーダーアセットを選択し、[Compile and show code]ボタンをクリックします。
f:id:bluebirdofoz:20200130092644j:plain

これにより、全てのシェーダーバリアントがコンパイルされ、その結果が Visual Studio で開きます。
生成される統計結果は、特定のシェーダーを使用するマテリアルで有効になっている機能によって異なる場合があります。
Unityは現在のプロジェクトで直接使用されているシェーダーバリアントのみをコンパイルします。
f:id:bluebirdofoz:20200130092736j:plain

Unity Standard シェーダーの統計例
f:id:bluebirdofoz:20200130092745j:plain

MRTK Standard シェーダーの統計例
f:id:bluebirdofoz:20200130092754j:plain