Unityパフォーマンスの最適化:結合されたバッチ

序文

このシリーズは、パフォーマンスの最適化に関する少しの知識であり、毎日のゲーム開発とパフォーマンスのポイントです。この記事は、このシリーズの記事の2番目の記事です。前の記事はリンクされています。

パート1:Unityパフォーマンスの最適化:リソース


初期Unityのバッチの処理方法は、主に次の3つでした。

  • Static Batching
  • Dynamic Batching
  • GPU Instancing

また、使用には厳しい制限があります。Unity発売後、SPRバッチ処理の範囲と効率を向上させるために、新しいバッチ処理方法が提供されSPR Batcherます。この記事では、これらのバッチ処理技術を簡単に紹介します。

ドローコール、バッチャー、サットパスコール

バッチ処理を理解する前に、CPU処理のレンダリングレートを測定するためのいくつかの参照値を理解する必要があります

  • Draw Call


Unityエンジンの初期段階では、レンダリングパイプラインでのCPUの処理段階は主にデータの準備と送信を行うためのアプリケーション段階であるため、レンダリング中のCPUのリソース消費は主に描画呼び出しの数によって測定されます。 Draw Callの処理段階はアプリケーション段階です。この数値は、CPUがGPUにデータを送信する回数を表します。DrawCall自体はデータストリームのほんの数バイトです。主なパフォーマンスの消費はデータにあります。 CPUの準備フェーズ。

  • Batcher

バッチ処理の出現により、すべてのレンダリングオブジェクトが描画呼び出しを生成するわけではないため、今回は新しいメジャーが提案されます:バッチャー

  • Set Pass Call

前述のようにCPU、レンダリング段階では、パフォーマンス消費のピークは一般Draw Callにデータ準備の段階ではないため、データ送信数を測定基準として使用することは正確ではありません。より多くのパフォーマンスを消費します。これは、CPUレンダリング段階全体で最もパフォーマンスを消費するステップでもあるためUnitySet Pass Callパフォーマンス消費の標準として使用されます。

主なバッチ技術の紹介

Unity以下は、中国で一般的に使用されているバッチ処理方法の簡単な説明です。これらの説明は主にUnity公式文書からのものであり、一部は直接コピーされており、情報は比較的正確です。

1、静的バッチ処理

Unity公式文書によるとStatic Batching、動作原理は次のとおりです。

  • 静的なゲームオブジェクトをワールドスペースに変換し、それらの共有頂点とインデックスバッファを構築します。
  • 有効Optimized Mesh Dataすると、頂点バッファを構築するときにシェーダーバリアントで使用されていない頂点要素を削除します。Unityこれを行うために、システムはいくつかの特別なキーワードチェックを実行します。たとえば、キーワードUnityが検出されない場合、ライトマップはバッチから削除されます。LIGHTMAP_ONUV
  • 一連の単純な描画呼び出しは、同じバッチ内の表示されているゲームオブジェクトに対して実行されUnity、各呼び出し間で状態はほとんど変化しません。技術的には、描画Unity呼び出しは削減されませんが、状態はそれらの間で変化します(これは多くのリソースを消費する部分です)。APIほとんどのプラットフォームでは、バッチ処理は64kの頂点と64kのインデックスに制限されています(OpenGLES48kのインデックスmacOSは、 32kのインデックスは)

簡単に言えば、Static Batchingいくつかの小さなメッシュをマージしてメモリに戻すことにより、レンダリング操作を実行するときに、マージされたCPUメモリを送信して一度に量GPUを減らしますが、特定の制限があります。Draw Call

  • オブジェクトは静的で移動できない必要があります
  • マージされたオブジェクトは同じマテリアルを使用します

同時に、Static Batching使用時に結合されたジオメトリを格納するために追加のメモリが必要になるため、ある程度のメモリの浪費が発生します。簡単に言えば、メモリを交換することで時間効率の良い操作が得られるため、CPUパフォーマンス上の利点を得る際に不要なメモリの問題を回避するために、実際の状況に応じてレンダリングオブジェクトを慎重に追加する必要があります。

使用に関しては、最初に次のオプションにチェックマークStatic Batchingを付ける必要がありますProject SettingPlayerStatic Batching
ここに画像の説明を挿入

次に、InspectorパネルでStatic Batching必要なオブジェクトを確認できます。Batching Static具体的な位置は次の図のようになります。

ここに画像の説明を挿入

2、動的バッチ処理

Dynamic Batchingオブジェクトを共通のマテリアルとマージすることもできますが、オブジェクトは動的である可能性があり、このプロセスは動的であるため、チェックボックスをオンにする必要がProject Settingあります。ただし、テンプレートでは、このオプションは構成ファイルに移動されています。特定の場所を図に示します。PlayerDynamic BatchingURPURP
ここに画像の説明を挿入

セットアップ手順は非常に簡単ですがDynamic Batching、その使用条件は非常に厳しく、バッチ処理の効果を達成するには一連の資格を満たす必要があります。Unity関係者はまた、ドキュメントに詳細なリストを作成しました。

  • 動的ゲームオブジェクトのバッチ処理には頂点ごとのオーバーヘッドがあるため、バッチ処理は、合計で900以下の頂点属性と300以下の頂点を含むメッシュにのみ適用されます。シェーダーが頂点位置、法線、および単一のUVを使用する場合、最大300の頂点をバッチ処理できますが、シェーダーが頂点位置、法線、UV0、UV1、および接線を使用する場合は、180の頂点のみをバッチ処理できます。

  • GameObjectの変換に鏡像がある場合、それらのオブジェクトはバッチ処理されません(たとえば、+1スケールのGameObjectAと-1スケールのGameObjectBを一緒にバッチ処理することはできません)。GameObjectが基本的に同じであっても、異なるマテリアルインスタンスを使用すると、GameObjectが一緒にバッチ処理されなくなります。例外はシャドウキャスターレンダリングです。

  • ライトマップを含むゲームオブジェクトには、ライトマップインデックスとライトマップオフセット/スケールという追加のレンダラーパラメータがあります。一般に、動的ライトマップのGameObjectは、バッチ処理されるまったく同じライトマップの場所を指している必要があります。
    マルチパスシェーダーはバッチ処理を中断します。

  • ほとんどすべてのUnityシェーダーは、フォワードレンダリングで複数のライトをサポートし、それらの追加パスを効果的に実行します。追加のピクセルごとのライトの描画呼び出しはバッチ処理されません。
    従来の遅延(ライティングプリパス)レンダリングパスは、ゲームオブジェクトを2回描画する必要があるため、動的バッチ処理を無効にします

たくさんあるように見えますが、簡単な要約では、モデルは単純であるShader必要があり、使用されるモデルは単一である必要がありますPass同時に、単一のPass制限のため、遅延レンダリングの場合、照明は別々のPass処理に分離されるため、照明されたオブジェクトは動的なバッチ処理操作を実行する方法がなく、直接ブロックされます。Dynamic Batching

3、GPUインスタンス化

GPU Instanceing少数の描画呼び出しで、同じメッシュの複数のコピーを一度に描画(またはレンダリング)するために使用します。建物、木、草など、シーンで繰り返されるオブジェクトを描画する場合に便利です。

  • GPU Instanceing各描画呼び出しで同じメッシュのみがレンダリングされますが、各インスタンスに異なるパラメーター(たとえば、色やスケール)を設定して、バリエーションを増やし、外観の繰り返しを減らすことができます。

  • GPU Instanceingシーンごとに使用される描画呼び出しの数を減らすことができます。プロジェクトのレンダリングパフォーマンスを大幅に向上させることができます。

他のバッチ処理方法と同様に、GPU Instanceingいくつかの使用制限もあります。

  • Unityインスタンス化してGraphics.DrawMesh呼び出す。サポートされていないことに注意してくださいSkinnedMeshRenderer

  • UnityGPU1回のインスタンス化された描画呼び出しで同じメッシュと同じマテリアルを共有するバッチゲームオブジェクトのみ。少数のメッシュとマテリアルを使用すると、インスタンス化の効率を向上させることができます。バリアントを作成するには、シェーダースクリプトを変更して、各インスタンスのデータを追加します

その説明の公式リンクは次のとおりです。GPUインスタンス化

上記は公式文書の説明GPU Instanceingです。他の2つのバッチ処理方法とは異なり、同じ材料に加えて、同じメッシュを使用するオブジェクトに主に有効であることがわかります。そのため、名前Instanceingが示すように、GPU直接です。オブジェクトをインスタンス化してCPU、シーンオブジェクトのデータコマンド準備のパフォーマンス消費を削減する技術的手段

4、SRPバッチャー

SRP Batcher公式ドキュメントへのリンク:SRP Batcher、公式ドキュメントに移動したくないかどうかは関係ありません。また、ここに直接移動して、説明テキストを追加しました。

SRPバッチを有効にする:
を使用するSRP Batcherには、プロジェクトでプログラム可能なレンダリングパイプラインを使用する必要があります。プログラム可能なレンダリングパイプラインは次のとおりです。

  • ユニバーサルレンダリングパイプライン(URP
  • HDレンダリングパイプライン(HDRP
  • カスタマイズSRP

後者の2つの方法は一般的に使用されないため、この記事はURPテンプレートに基づいて紹介されURPます。具体的な詳細については、この記事を確認してください:Urp(Universal Rendering Pipeline)へのUnityアップグレードプロジェクトと画面の後処理

プロジェクトでURPテンプレートを使用するURPと、現在のプロジェクトの構成ファイルがリソースディレクトリにありSRP Batcher、制御オプションが表示されます。
ここに画像の説明を挿入

同時に、プロジェクトがURPテンプレートの下にある場合、スイッチ制御オプションも構成ファイルに移行されますが、デフォルトのレンダリングパイプラインとDynamic Batching比較すると、このテクノロジは、SRP Batcher

SRPバッチャーの原則:

Unity、任意のマテリアルのプロパティは、フレーム内でいつでも変更できます。ただし、このアプローチにはいくつかの欠点があります。たとえばDrawCall、新しい素材を使用する場合、やるべきことがたくさんあります。したがって、シーン内のマテリアルが多いほどデータのUnity設定に使用する必要があります。この問題を解決する従来の方法は、レンダリングコストを最適化するために数を減らすことです。これは、が放出される前に多くのセットアップを行う必要があるためです。実際のコストは、それ自体からではなく、その設定から発生します(コマンドバッファーにプッシュする必要がある数バイトのみ)GPUCPUDrawCallCPUUnityDrawCallCPUGPU DrawCallDrawCallUnityGPU

説明で説明したようSet Pass Callに、レンダリング段階でCPUのゲームのパフォーマンス消費は、主にマテリアル切り替え段階でのいくつかのタスクに関連しており、新しいマテリアルの準備時間は、データバッファSPR Batcher内のデータGPUバッファの永続的な保存と交換されます、それによってデータ準備の圧力CPUを減らします。CPU

SRP Batcher一連のコマンドBindコマンドDraw GPUをバッチ処理することにより、設定を減らします。特定のプロセスを図に示します。DrawCallGPU
ここに画像の説明を挿入

レンダリングパフォーマンスを最大にするには、これらのバッチをできるだけ大きくする必要があります。これを実現するには、同じシェーダーでできるだけ多くの異なるマテリアルを使用できますが、使用するシェーダーのバリエーションはできるだけ少なくする必要があります。

内側のレンダリングループでUnityは、新しいマテリアルが検出されると、CPUすべてのプロパティが収集され、さまざまな定数バッファがGPUメモリ。GPUバッファの数は、シェーダがその宣言方法によって異なります。CBUFFER

シーンが多くの異なるマテリアルを使用しているがシェーダーバリアントがほとんどない一般的なケースで処理を高速化するために、SRPパラダイムをネイティブに統合します(GPUデータの永続性など)

SRP Batcherは、マテリアルデータをGPUメモリ内。マテリアルの内容が変更SRP Batcherされない場合は、バッファを設定してバッファをアップロードする必要はありませんGPU実際、SRP Batcher専用のコードパスを使用しGPUUnity、次のような大きなバッファーのエンジンプロパティをすばやく更新します。
ここに画像の説明を挿入

これがSRP Batcherレンダリングワークフローです。SRP Batcher専用のコードパスを使用して、大きなGPUバッファーのUnityエンジンプロパティをすばやく更新します。ここでCPUは、上の画像のようにPer Object large bufferマークたUnityエンジンプロパティのみが処理されます。すべての資料はGPUメモリCBUFFERされ、いつでも使用できます。これにより、レンダリングが高速化されます。理由は次のとおりです。すべてのマテリアルコンテンツがGPUメモリた。専用コードは、すべてのオブジェクトごとのプロパティの大きなオブジェクトごとのプロパティを管理しますGPU CBUFFER

SRPバッチャーの制限:

SRP Batcherコードパスでオブジェクトをレンダリングできるようにするには:

  • レンダリングされるオブジェクトは、メッシュまたはスキンメッシュである必要があります。オブジェクトをパーティクルにすることはできません。

  • シェーダーはとSRP Batcher互換性がある。すべての点灯およびHDRP消灯シェーダーがこの要件を満たしています(これらのシェーダーの「パーティクル」バージョンを除く)。シェーダーをSRPバッチャーと互換性を持たせるには:URP

  • すべての組み込みエンジンプロパティは、名前付きで宣言する必要UnityPerDrawあります。CBUFFERたとえばunity_ObjectToWorldまたはunity_SHAr

  • すべての材料特性UnityPerMaterialCBUFFER

バッチパフォーマンステスト用

従来のバッチ:

一般的に、バッチ処理はシーンレンダリングのデータ処理を減らし、それによってCPUレンダリング中のプレッシャーを減らすことです。Unityパフォーマンス分析ツールを使用Profilerすると、それに関連する値を簡単に確認できます。

ここに画像の説明を挿入

クリックRenderingして、参加、、、および3つのバッチ処理テクノロジーなどのパラメーターの数にOpen Frame Debugger固有のバッチ処理に関連する知識をパネルに表示しますStatic BatchingDynamic BatchingGPU InstancingDraw Call

もちろん、CPUパフォーマンスの消費を分析してCPU、セグメントのボトルネック情報を取得することもできます。
ここに画像の説明を挿入

をクリックするCPU Usageと、下のパネルで確認できますBatchRendener.Flush。これは、レンダリングパフォーマンスに影響を与える可能性のある非常に注目に値するCPUパラメータでありSelf、時間のかかる現在の影響を評価できCPUます。

展開すると、最大4つのサブオプションが表示されます。

  • Render.MeshCPUバッチ処理できない対応して処理されたオブジェクト
  • Batch.DrawInstanced:処理に対応CPUするGPU Instancing処理対象の場合
  • Batch.DrawStaticCPU処理される対応するStatic Batchingオブジェクト
  • Batch.DrawDynamicCPU処理される対応するDynamic Batchingオブジェクト

上記のスクリーンショット分析のシナリオでは、バッチプロセス全体のリソース消費を分析し、それと時間の統計を作成するために、それぞれに1つを配置、異なるバッチ操作を実行しまし30000このバッチメソッドはここでは削除されています。シーン内のオブジェクトの特定のバッチメソッドは次のとおりです。CubeDraw CallDynamic BatchingCPU

  • 10000オブジェクト:Static Batching
  • 10000オブジェクト:GPU Instancing
  • 10000オブジェクト:Dynamic Batching
  • 2つの追加オブジェクト:処理されません

Profilerパフォーマンスパフォーマンスの監視を通じてCPU、3つのバッチ処理方法の運用効率は静的バッチ処理で最も高く、GPU Instancing比較的Dynamic Batching劣っています。シーンにオブジェクトが多数ある場合、観測された値は注目に値します。上記の分析方法で得られたものを表示しますGPU Instancing。時間はそれ以上ですが、実際にはレンダリング段階全体Dynamic Batchingでの2つのバッチ技術の合計時間は逆になります。モードを切り替える結果がはっきりとわかります。に:CPUProfileHierarchyTimeLine

ここに画像の説明を挿入

上図からわかるように、Dynamic Batchingそれ自体で発生する時間(下の短い段落の合計)は比較的小さいですが、対応するBatchRendener.Flush(上の段落)の時間が長くなるため、分析しています。使用におけるそれらの利点。、TimeLine全体的な時間のかかる状況を分析するためにモードに切り替えることができます

具体BatchRendener.Flush的な内容は、公式フォーラムの技術者の説明から理解できますUnity。その人の元の言葉は次のとおりです。
ここに画像の説明を挿入

SRPバッチャー:

プロジェクトでオンにすると、ブロッキングSRP Batcherと同じように他のバッチ処理方法が機能しなくなることがわかりますが、違いは、この部分の特定のドキュメントの説明がなく、単純な仮定であるということです。ただし、このステートメントを確認するための実験を行うだけで済みます。オンになっていない場合は、いくつかの特定のオブジェクトに動的バッチ処理を使用すると、静的バッチ処理が正常に実現されていることがわかります。次に、スイッチをオンにした後、次のようにします。Static BatchingGPU InstancingSRP BatcherProfiler
ここに画像の説明を挿入
SRP Batcher
ここに画像の説明を挿入

したがって、ここでは、他のバッチ処理方法がブロックされることを簡単に理解できます。パフォーマンスの消費SRP Batcherを観察したい場合は、図に示すように、それSRP Batcherを直接見つけることができます。TimeLineSRP Batcher.Flush
ここに画像の説明を挿入

要約する

中国でのバッチ処理方法についてUnityは、上記の成熟した効果的な方法がいくつかありますが、それぞれ長所と短所があります。実際のアプリケーションシナリオに応じて適切な方法を選択する必要があります。つまり、メモリバジェットが非常に限られている場合は、メモリの負荷の増加を避けるために、静的バッチ処理を考慮しないでください。これらの技術的メリットを享受するときに支払う価格を忘れないでください

おすすめ

転載: blog.csdn.net/xinzhilinger/article/details/121121772