Hero background image

PCおよびコンソールゲームのGPU使用率の管理

このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。

この記事は、Unityプロジェクトの最適化のヒントを紐解くシリーズの第3弾です。より少ないリソースでより高いフレームレートで実行するためのガイドとしてご利用ください。これらのベストプラクティスを試したら、シリーズの他のページもぜひご覧ください。

ターゲットハードウェアの制限と、グラフィックスのレンダリングを最適化するための GPU のプロファイリング方法を理解します。GPU のワークロードを減らすためのヒントやベストプラクティスをお試しください。

無料の e ブック「Optimize your game performance for console and PC」では、他にも多くのベストプラクティスを紹介しています。

Unity エンジンの SRP Batcher
SRP BATCHER は描画コールをバッチ化するのに役立ちます。

ドローコールバッチ処理の使用

画面にゲームオブジェクトを描画するために、UnityはグラフィックスAPI(OpenGLVulkanDirect3Dなど)にドローコールを発行します。各ドローコールはリソースを大量に消費します。

マテリアルの切り替えなど、描画コール間の状態変化は、CPU 側でパフォーマンスのオーバーヘッドを引き起こす可能性があります。PC およびコンソールハードウェアは、多くの描画コールをプッシュできますが、各コールのオーバーヘッドは依然として高く、その削減を保証するには十分です。モバイルデバイスでは、ドローコール最適化が不可欠です。これは、ドローコールバッチ処理で実現できます。

ドローコールバッチ処理は、これらの状態変化を最小限に抑え、オブジェクトのレンダリングにかかる CPU コストを削減します。Unityは、HDレンダーパイプライン(HDRP)またはユニバーサルレンダーパイプライン(URP)のいくつかの手法を使用して、複数のオブジェクトをより少ないバッチにまとめることができます。

  • SRPバッチ処理上級者向けパイプライン アセットSRP Batcherを有効にします。互換性のあるシェーダーを使用している場合、SRP Batcherは描画コール間のGPU設定を減らし、マテリアル データをGPUメモリに永続化します。これにより、CPU のレンダリング時間を大幅にスピードアップすることもできます。最小限のキーワードでシェーダーバリアントを少なくして、SRPバッチ処理を改善します。プロジェクトでこのレンダリングワークフローを活用する方法については、SRPドキュメントを参照してください。
  • GPUインスタンシング:同じメッシュとマテリアルを持つ同一のオブジェクトが多数ある場合は、GPUインスタンシングを使用してグラフィックスハードウェアを通じてバッチ処理を行います。GPU インスタンシングを有効にするには、InspectorProject ウィンドウでマテリアルを選択し、Enable instancing をオンにします。
  • 静的バッチ処理:動かないジオメトリの場合、Unityは同じマテリアルを共有するメッシュの描画コールを削減できます。これはダイナミックバッチ処理よりも効率的ですが、より多くのメモリを使用します。Inspector で、動かないすべてのメッシュをバッチ処理静的としてマークします。Unityはビルド時にすべての静的メッシュを1つの大きなメッシュに統合します。StaticBatchingUtility クラスでは、静的バッチをランタイム (例えば、プロシージャルレベルの可動部品を生成した後) で作成することもできます。
  • 動的バッチ処理:小さなメッシュの場合、UnityはCPU上で頂点をグループ化してTransformし、一度にすべて描画できます。ただし、十分な数のローポリゴンメッシュ(各頂点が 300 以下、合計頂点属性が 900 以下)がない限り、この方法は使用しないでください。そうしないと、バッチ処理する小さなメッシュを探すのに CPU 時間を浪費してしまいます。

バッチ処理を最大化する方法はいくつかあります。

  • シーンで使用するテクスチャはできるだけ少なくする。テクスチャの数が少ないほど、必要な固有マテリアルの数も少なくなり、バッチ処理が容易になります。さらに、可能な限りテクスチャアトラスを使用します。
  • ライトマップを常に可能な限り大きなアトラス サイズでベイクする。ライトマップが少ないほど、マテリアル状態の変更も少なくて済みますが、メモリフットプリントに注意してください。
  • 意図せずにマテリアルをインスタンス化しないように注意してください。スクリプトで Renderer.マテリアルにアクセスすると、マテリアルが複製され、新しいコピーへの参照が返されます。これにより、マテリアルがすでに含まれている既存のバッチがすべて破棄されます。バッチ処理されたオブジェクトのマテリアルにアクセスする場合は、代わりに Renderer.sharedMaterial を使用します。
  • 最適化中にプロファイラーまたはレンダリング統計を使用して、静的およびダイナミックバッチ数とドローコール数の合計を常に監視します。

詳細については、ドローコールバッチ処理のドキュメントを参照してください。

フレームデバッガーのインターフェース
フレームデバッガーは、レンダリングされた各フレームを分割します。

フレームデバッガーを確認する

フレームデバッガーを使用して 1 フレームでの再生をフリーズし、Unity がシーンを構築するプロセスをステップごとに実行します。そうすることで、最適化の機会を特定できます。不必要にレンダリングされるゲームオブジェクトを探し、それらを無効にしてフレームごとの描画コールを減らします。

フレームデバッガーの主な利点の 1 つは、ドローコールをシーン内の特定のゲームオブジェクトに関連付けできることです。これにより、外部フレームデバッガーでは不可能な特定の問題の調査が容易になります。

注:フレームデバッガーには、個々の描画呼び出しや状態の変化は表示されません。ネイティブ GPU プロファイラーだけがドローコールとタイミングに関する詳細情報を提供できますが、フレームデバッガーはパイプラインの問題やバッチ処理の問題のデバッグに非常に役立ちます。

詳細については、フレームデバッガードキュメントを参照してください。

フィルレートを最適化し、オーバードローを削減

フィルレートとは、GPUが1秒間に画面にレンダリングできるピクセル数のことです。ゲームがフィルレートによって制限されている場合は、GPUがハンドルできるよりも多くのピクセルをフレームごとに描画しようとしていることを意味します。

同じピクセルの上に複数回描画することをオーバードローと呼びます。オーバードローはフィルレートを下げ、余分なメモリ帯域幅を消費します。オーバードローの最も一般的な原因は、次のとおりです。

  • 不透明または透明なジオメトリのオーバーラップ
  • シェーダーが複雑で、多くの場合、複数のレンダーパスが必要
  • 最適化されていないパーティクル
  • UI 要素の重複

その効果は最小化する必要がありますが、オーバードローを解決するための万能のアプローチはありません。その影響を軽減するために、以下のテクニックを試してください。

バッチ数を減らす

他のプラットフォームと同様に、コンソールでの最適化はドローコールバッチの削減を意味することが多いです。ヘルプとなるテクニックをいくつか紹介します。

  • オクルージョンカリングを使用して、フォアグラウンドオブジェクトの後ろに隠れたオブジェクトを削除し、オーバードローを減らします。これには追加の CPU 処理が必要なので、プロファイラーを使用して、GPU から CPU への移行作業が実際に有益であることを確認します。
  • GPUインスタンシングは、同じメッシュとマテリアルを共有するオブジェクトが多数ある場合に、バッチを減らすこともできます。シーン内のモデル数を制限すると、パフォーマンスが向上します。これを巧妙に行えば、複雑なシーンを繰り返し見せることなくビルドできます。
  • SRP Batcherは、GPUコマンドのバインド描画をバッチ処理することで、描画呼び出し間のGPU設定を削減できます。このSRPバッチ処理のメリットを享受するには、必要なだけマテリアルを使用し、互換性のある少数のシェーダー(URPやHDRPではLitシェーダーとUnlitシェーダーなど)に限定します。
オクルージョンカリングのインターフェース
オクルージョンカリングの例。

カリングに注意する

カリングはカメラごとに発生し、特に複数のカメラを同時に有効にすると、パフォーマンスに大きな影響を与える可能性があります。Unity は 2 種類のカリングを使用します。

  • 錐台カリングはすべてのカメラで自動的に実行されます。視錐台外のゲームオブジェクトがレンダリングされないため、パフォーマンスを節約できます。
  • レイヤーごとのカリング距離は、Camera.layerCullDistances から手動で設定できます。これにより、デフォルトの farClipPlane プロパティよりも短い距離で小さなゲームオブジェクトをカリングできます。これを行うには、ゲームオブジェクトをレイヤーに整理します。.layerCullDistances 配列を使用して、32 の各レイヤーに farClipPlane より小さい値を割り当てます (デフォルトの farClipPlane には 0 を使用します)。
  • Unity はまずレイヤーごとにカリングします。カメラが使用するレイヤーにのみゲームオブジェクトを保持します。その後、錐台カリングによってカメラ錐台外のゲームオブジェクトが削除されます。
  • 錐台カリングは、使用可能なワーカースレッドを利用する一連のジョブとして実行されます。各レイヤー カリング テストは迅速です(基本的にはビット マスク操作のみ)。ただし、このコストはゲームオブジェクトの数が多いと膨らむ可能性があります。これがプロジェクトで問題になった場合は、Unity のレイヤー/錐台カリングシステムにかかる負荷をいくらか軽減するために、ワールドを「セクター」に分割し、カメラ錐台台の外側にあるセクターを無効にするシステムを実装する必要があるかもしれません。
  • オクルージョンカリングは、カメラに映らないゲームオブジェクトをゲームビューから削除します。他のオブジェクトの後ろに隠れているオブジェクトは、依然としてレンダリングされ、リソースが消費される可能性があります。オクルージョンカリングを使用して破棄します。
  • 例えば、ドアが閉じていてカメラから部屋が見えない場合、部屋のレンダリングは不要です。オクルージョンカリングを有効にすると、パフォーマンスが大幅に向上するだけでなく、より多くのディスク領域、CPU 時間、RAM を消費できます。Unityはビルド中にオクルージョン データをベイクし、シーンのロード中にディスクからRAMにロードする必要があります。
  • カメラ ビュー外の錐台カリングは自動ですが、オクルージョンカリングはベイク処理です。オブジェクトを静的オクルーダーオクルードとしてマークし、「ウィンドウ」>「レンダリング」>「オクルージョンカリング」ダイアログでベイクします。

詳細については、 オクルージョンカリングの操作 チュートリアルを参照してください。

動的解像度の活用

Allow Dynamic Resolution Camera(動的解像度カメラを許可)」設定では、個々のレンダーターゲットを動的にスケールして、GPUのワークロードを軽減できます。アプリケーションのフレームレートが低下した場合は、解像度を徐々にスケールダウンして一貫したフレームレートを維持できます。

Unity は、GPU バウンドの結果としてフレームレートが低下しようとしていることをパフォーマンデータから示唆している場合に、このスケーリングをトリガーします。このスケーリングは、スクリプトを使用して手動で事前にトリガーすることもできます。これは、アプリケーションの GPU を多用するセクションに差し掛かる場合に便利です。徐々にスケーリングすれば、動的解像度はほとんど気にならなくなります。

サポートされているプラットフォームのリストについては、動的解像度マニュアルページを参照してください。

カメラスタッキングのデモ
URP でスタッキングするカメラ:カメラの設定が異なる銃と背景のレンダラー。

複数のカメラビューを確認する

ゲーム中に複数のビューからレンダリングする必要がある場合があります。例えば、一人称シューティングゲーム(FPS)では、プレイヤーの武器と環境を異なる有効ビュー(FOV)で別々に描画のが一般的です。これにより、背景の角度 FOV を通して前景のオブジェクトが歪んで見えるのを防ぐことができます。

URP でカメラスタッキングを使用すると、複数のカメラビューをレンダリングできます。ただし、各カメラではまだかなりのカリングとレンダリングが行われます。各カメラは、意味のある仕事をしているかどうかにかかわらず、オーバーヘッドが発生します。

レンダリングに必要なカメラコンポーネントのみを使用してください。モバイルプラットフォームでは、何もレンダリングしていないときでも、アクティブなカメラはすべて最大1ミリ秒のCPU時間を消費できます。

LOD使用

オブジェクトが遠くに移動すると、LOD(Level of Detail)は、よりシンプルなマテリアルとシェーダーで低解像度のメッシュを使用するように調整または切り替えます。これにより、GPU のパフォーマンスが強化されます。

詳細については、Unity LearnのWorking with LODsコースを参照してください。

ポストプロセスインターフェース
ポストプロセスエフェクトをできるだけシンプルに維持します。

ポストプロセスエフェクトのプロファイル

ポストプロセスエフェクトをプロファイリングして、GPU のコストを確認します。ブルーム被写界深度などの全画面エフェクトの中には、コストのかかるものもあります。そのため、ビジュアル品質とパフォーマンスの望ましいバランスが見つかるまで試してみる価値はあります。

ポストプロセッシングはランタイム時にあまり変動しません。音量オーバーライドを決定したら、合計フレームバジェットの静的部分をポストプロセスエフェクトに割り当てます。

テッセレーションシェーダーの使用を避ける

テッセレーションは、形状自体を小さなバージョンに分割し、ジオメトリを増やすことでディテールを強化できます。テッセレーションが最も適している例は、Unity デモ『Book of the Dead』の樹木の樹皮などですが、コンソールでのテッセレーションは GPU 負荷が高いため避けてください。

Book of the Dead』のデモの詳細については、こちらを参照してください。

ジオメトリシェーダーをコンピュートシェーダーに置き換える

テッセレーション シェーダーと同様に、ジオメトリ シェーダーと頂点シェーダーは、GPUでフレームあたり2回実行できます。1回は深度プリパス中、もう1回はシャドウ パス中になります。

GPU で頂点データを生成または変更する場合は、特にジオメトリシェーダーと比較して、コンピュートシェーダーが適していることが多いです。コンピュートシェーダーで処理を行うことで、ジオメトリを実際にレンダリングする頂点シェーダーの動作を大幅に高速化できます。

シェーダーコア概念の詳細をご覧ください。

ウェーブフロントの占有率のグラフの良し悪し
ウェーブフロントの占有率の良し悪し

良好なウェーブフロント占有率を目指す

GPUにドローコールを送信すると、その処理は多くのウェーブフロントに分割され、UnityはGPU内の利用可能なSIMD全体に分散します。各 SIMD には、同時に実行できるウェーブフロントの最大数があります。

ウェーブフロントの占有率とは、最大数に対して現在使用されているウェーブフロントの数のことです。GPU のポテンシャルをどれだけうまく活用しているかを測定します。コンソール開発用のプロファイリングツールは、ウェーブフロントの占有率を詳細に表示します。

Unityの『Book of the Dead』の上の例では、頂点シェーダーのウェーブフロントが緑色で表示され、ピクセルシェーダーのウェーブフロントが青で表示されています。下のグラフでは、多くの頂点シェーダーのウェーブフロントが、ピクセルシェーダーがほとんど使用されていない状態で表示されています。これは、GPU が十分に活用されていないことを示しています。

ピクセル数につながらない頂点シェーダー処理を多数行っている場合は、非効率性を示している可能性があります。ウェーブフロントの占有率が低いことは必ずしも悪いことではありませんが、シェーダーの最適化や他のボトルネックのチェックを開始するために使用できる指標です。例えば、メモリや演算処理が原因でストールが発生した場合、占有率を上げることでパフォーマンスを向上させることができます。一方、処理中のウェーブフロントが多すぎると、キャッシュスラッシングが発生し、パフォーマンスが低下する可能性があります。

非同期コンピューティングを活用する

GPU を十分に活用していないインターバルがある場合は、非同期コンピュートを活用してコンピュートシェーダーの処理をグラフィックスキューに並列移動させることができます。例えば、シャドウマップの生成中、GPUは深度のみのレンダリングを実行します。この時点ではピクセルシェーダー処理はほとんど行われず、多くのウェーブフロントが占有されないままになっています。

コンピュートシェーダーの処理を深度のみのレンダリングと同期させることができれば、GPUの全体的な使用率が向上します。未使用のウェーブフロントは、スクリーンスペースアンビエントオクルージョン(SSAO)や現在の作業を補完するタスクに役立ちます。

Uniteのハイエンド コンソールのパフォーマンス最適化に関するセッションを視聴してください。

Unity キー 21 11
無料の e ブックを入手する

最も包括的なガイドの1つは、ゲームをPCおよびコンソール向けに最適化する方法に関する80を超える実用的なヒントを集めたものです。Unity のエキスパートである Success と Accelerate Solutions のエンジニアが作成したこれらの深度なヒントは、Unity を最大限に活用し、ゲームのパフォーマンスを高めるのにヘルプます。