今回は、Unityプロジェクトの最適化のヒントを紹介する連載の第1回目です。より少ないリソースでより高いフレームレートで動作させるためのガイドとしてご利用ください。これらのベスト・プラクティスを試したら、シリーズの他のページもぜひご覧ください:
アセット・パイプラインは、チームの生産性と試合のパフォーマンスに劇的な影響を与えます。経験豊富なテクニカルアーティストと協力することで、チームは円滑なプロセスのためにアセットフォーマットや仕様を定義し、実施することができるようになります。
デフォルト設定に頼らないこと。テクスチャやメッシュジオメトリなどのアセットを最適化するには、プラットフォーム固有のオーバーライドタブを使用します。設定が正しくない場合、ビルドサイズが大きくなり、ビルド時間が長くなり、GPUパフォーマンスとメモリ使用量が低下する可能性があります。プリセット機能を使用して、プロジェクトのベースライン設定をさらにカスタマイズすることを検討してください。
アートアセットを扱う際のベストプラクティスについては、こちらのガイドをご覧ください。モバイルに特化したガイドについては、モバイルアプリケーションの3Dアート最適化に関するUnity Learnコースをご覧ください。
Player Settingsで、Auto Graphics APIを 無効にし、ターゲットとする各プラットフォームでサポートする予定のない追加のグラフィックスAPIを削除してください。これにより、過剰なシェーダーバリアントの生成を防ぐことができる。アプリケーションが古いCPUをサポートしていない場合は、Target Architectures 設定を無効にしてください。
Graphics APIについて詳しくはこちらをご覧ください。
スクリプトのバックエンドをMonoから IL2CPP(Intermediate Language to C++)に切り替えると、全体的に実行時のパフォーマンスが向上する。しかし、製造時間が長くなる可能性もある。開発者の中には、Monoをローカルで使い、より速いイテレーションを行い、ビルドマシンやリリース候補をIL2CPPに切り替えることを好む人もいる。ビルド時間の短縮については、IL2CPPビルド時間の最適化ドキュメントを参照してください。
注:このオプションを使用すると、UnityはスクリプトとアセンブリのILcodeをC++に変換してから、ターゲットプラットフォーム用のネイティブバイナリファイル(.exe、.apk、.xap)を作成します。
さまざまなコンパイラ・オプションが実行時のパフォーマンスにどのように影響するかについては、IL2CPP内部入門を参照するか、コンパイラ・オプションのマニュアル・ページを参照してください。
モバイルプロジェクトでは、フレームレートとバッテリー寿命やサーマルスロットリングのバランスを取る必要がある。1秒あたりのフレーム数(fps)を考えてみよう。
60fpsでデバイスの限界に挑戦するのではなく、妥協案として30fpsでの実行を検討してください。なお、Unityのモバイル向けデフォルトはすでに30fpsになっている。
また、Application.targetFrameRateを使って、実行時にフレームレートを動的に調整することもできます。例えば、低速または比較的静的なシーン(メニューなど)では30fps以下に落とし、ゲームプレイでは高いfps設定を予約することができます。
モバイルプラットフォームはハーフフレームをレンダリングしない。エディターでVsyncを無効にしても(Project Settings > Quality)、ハードウェアレベルでは有効です。GPUが十分に速くリフレッシュできない場合、現在のフレームが保持され、結果としてfpsが低下します。
詳細はドキュメントを参照されたい。
Unityは携帯電話の加速度センサーを1秒間に数回ポーリングします。アプリケーションで使用していない場合は無効にするか、パフォーマンスを向上させるために頻度を減らしてください。
加速度センサーの詳細
階層を分ける。GameObjectを Hierarchyにネストさせる必要がない場合は、ペアレンティングをシンプルにします。
小さな階層は、シーン内のTransformsをリフレッシュするためにマルチスレッドの恩恵を受けます。複雑な階層は、不必要なTransformの計算とガベージコレクション (GC)のコストを発生させる。
トランスフォームのヒントについては、階層の最適化とこのUnite講演を参照してください。
上の2つの例では、同じモデルとテクスチャを使用していますが、上の設定は下の設定に比べて5倍以上のメモリを消費し、ビジュアルクオリティはそれほど向上していません。
テクスチャ圧縮を正しく適用すると、ロード時間の短縮、メモリフットプリントの縮小、レンダリングパフォーマンスの飛躍的向上など、パフォーマンスに大きなメリットがあります。圧縮テクスチャは、非圧縮32ビットRGBAテクスチャに必要なメモリ帯域幅のほんの一部しか使用しません。
ターゲットプラットフォームのテクスチャ圧縮フォーマットの推奨リストを参照してください。
テクスチャは過剰なリソースを使用する可能性があるため、インポート設定を最適化することが重要です。一般的には、以下のガイドラインに従うようにしてください:
- 最大サイズを下げる:視覚的に許容できる結果が得られる最小限の設定を使用する。これは非破壊的で、テクスチャのメモリをすぐに減らすことができる。
- 2のべき乗(POT)を使用:Unityは、テクスチャ圧縮フォーマットに対してPOTテクスチャ寸法を要求します。
- Read/Write Enabled オプションをオフに切り替える:このオプショ ンを有効にすると、CPU と GPU のアドレス可能なメモリの両方にコ ピーが作成され、テクスチャのメモリフットプリントが 2 倍にな ります。ほとんどの場合は無効にし、実行時にテクスチャを生成して上書きする必要がある場合のみ有効にします。このオプションは、Texture2D.Applyで makeNoLongerReadableを Trueに設定して渡すことで強制することもできます。
- 不要なMip Mapsを無効にする:Mip Mapsは、2Dスプライトや UIグラフィックスなど、画面上で一定のサイズを保つテクスチャには必要ありません。ただし、カメラからの距離が異なる3Dモデルの場合は、ミップマップを有効のままにしてください。
テクスチャのインポート設定について詳しくはこちら。
アトレーシングとは、複数の小さなテクスチャを1つの大きなテクスチャにまとめる作業のこと。テクスチャ・アトラスはメモリ使用量を減らし、必要な描画コールを少なくすることで、GPUが必要とする労力を減らします。
- 2Dプロジェクトの場合:スプライト スプライトアトラス(アセット > 作成 > 2D > スプライトアトラス)を使用します。
- 3Dプロジェクト用:ご希望のデジタル・コンテンツ・クリエーション(DCC)パッケージをご利用いただけます。のようないくつかのサードパーティツールがあります。 MA_TextureAtlasserや テクスチャパッカーのようなサードパーティ製のツールも、テクスチャアトラスの構築に使用できます。
高解像度マップを必要としないあらゆる3Dジオメトリに対して、テクスチャを組み合わせてUVをリマップできます。ビジュアルエディタにより、テクスチャアトラスやスプライトシートのサイズや位置を設定し、優先順位をつけることができます。
Texture Packerは、個々のマップを1つの大きなテクスチャに統合します。その後、Unityは1回のドローコールを発行して、パックされたテクスチャにアクセスし、パフォーマンスのオーバーヘッドを少なくすることができます。
スプライトアトラスについて詳しくはこちら
高解像度のモデルは、より多くのメモリ使用量を必要とし、GPUにより多くの仕事をさせる可能性がある。そのため、シーン内のGameObjectの幾何学的な複雑さは最小限に抑えるようにしましょう。そうしないと、Unityは重要な頂点データをグラフィックカードにプッシュしなければならない。
ベストプラクティスは、DCCソフトウェアでモデルをカットダウンし、カメラの視点から見えないポリゴンを削除することです。例えば、食器棚の背面が壁に当たっているのを見たことがなければ、モデルにはそこに顔はないはずだ。
最近のGPUでは、ボトルネックは通常、ポリゴン数ではなくポリゴン密度に関係していることに注意してください。遠くのオブジェクトのポリゴン数を減らすために、すべてのアセットでアートパスを実行するようにしてください。マイクロトライアングルはGPU性能低下の重大な原因となります。
ターゲットとするプラットフォームにもよりますが、ローポリジオメトリを補うために、高解像度のテクスチャでディテールを追加することを考えましょう。メッシュの密度を上げる代わりに、テクスチャと法線マップを使う。テクスチャにできるだけディテールを焼き込むことで、ピクセルの複雑さを減らす。たとえば、フラグメントシェーダでハイライトを計算しないように、テクスチャ自体にスペキュラハイライトを取り込むことができます。
定期的にプロファイリングすることを忘れずに。結局のところ、これらのテクニックはパフォーマンスに影響を与え、ターゲットとするプラットフォームには適していないかもしれない。
テクスチャと同様、メッシュも注意深くインポートしないと、過剰なメモリを消費することがある。メッシュのメモリ消費を最小限に抑えるために、以下のヒントを試してみてください:
- メッシュ・コンプレッション:メッシュ圧縮は、ディスク容量を削減することができます(ただし、実行時のメモリは影響を受けません)。同時に、メッシュの量子化は不正確になる可能性があるので、圧縮レベルを試して、あなたのモデルに何が有効かを確認してください。
- Disable Read/Write:このオプションを有効にすると、メモリ上にメッシュが複製され、メッシュのコピーが1つシステムメモリに、もう1つがGPUメモリに保持されます。ほとんどの場合、無効にしてください。Unity 2019.2以前では、このオプションはデフォルトでチェックされています。
- リグとブレンドシェイプを無効にする:メッシュにスケルタルやブレンドシェイプのアニメーションが必要ない場合は、これらのオプションを無効にしてください。
- 法線と接線を無効にする:メッシュのマテリアルに法線や接線が必要ないことが確実な場合は、これらのオプションのチェックを外すと、さらに節約できます。
その他のメッシュ最適化オプションは、プレイヤー設定で利用できます:
- 頂点圧縮は、各チャンネルの頂点圧縮を設定します。例えば、ポジションとライトマップUV以外のすべての圧縮を有効にすることができます。これにより、メッシュの実行時のメモリ使用量を減らすことができる。
- 注:各メッシュのImport SettingsにあるMesh Compression設定は、Vertex Compression設定よりも優先されます。その場合、メッシュのランタイムコピーは圧縮されず、より多くのメモリを使用する可能性がある。
- メッシュデータの最適化(Optimize Mesh Data)は、メッシュに適用されているマテリアルが必要としないデータ(タンジェント、法線、カラー、UVなど)をメッシュから削除します。
監査プロセスを自動化することで、資産の設定を誤って変更してしまうことを防ぐことができます。アセット アセットポストプロセッサは、インポート設定を標準化したり、既存のアセットを分析したりするのに役立ちます。アセットをインポートする際にスクリプトを実行することができ、基本的には、モデル、テクスチャ、オーディオなどをインポートする前や後に、設定をカスタマイズするよう促します。
資産監査については、「最適化を理解する」ガイドをお読みください。
Unityはリングバッファを使ってテクスチャをGPUにプッシュします。この非同期テクスチャバッファは、QualitySettings.asyncUploadBufferSizeで手動で調整できます。
アップロード速度が遅すぎるか、複数のテクスチャを一度にロードしている間にメインスレッドがストールする場合は、これらのテクスチャバッファを調整します。通常、この値(MB単位)は、シーンにロードする必要がある最大のテクスチャのサイズに設定できます。
デフォルト値を変更すると、メモリを圧迫する可能性があることに留意してください。また、Unityがリングバッファのメモリを確保した後、システムに戻すことはできません。GPUのメモリがオーバーロードした場合、GPUは最新で最も使用されていないテクスチャをアンロードし、次にCameraフラ ンスラムに入ったときにCPUに再アップロードさせます。
メモリ管理チュートリアルでテクスチャバッファのすべてのメモリ制限を調べ、ローディングパフォーマンスの最適化でローディング時間を改善する方法を参照してください。
ミップマップ ミップマップストリーミングシステムでは、どの Mip Map レベルをメモリにロードするかをコントロールすることができます。Unityの Quality設定(Edit > Project Settings > Quality)でTexture Streamingオプションをチェックして有効にします。詳細設定(Advanced)のテクスチャインポート設定(Texture Import Settings)でストリーミングミップマップ(Streaming Mip Maps)を有効にできます。
このシステムでは、現在のカメラ位置のレンダリングに必要なミップマップのみをロードするため、テクスチャに必要なメモリの総量が削減されます。そうでなければ、Unityはデフォルトですべてのテクスチャをロードします。
テクスチャ・ストリーミングは、大量のGPUメモリを節約するために、少量のCPUリソースを交換します。また、ユーザー定義のメモリーバジェット内に収まるように、ミップマップレベルを自動的に下げる。
Mip Map Streaming APIを使用することで、さらにコントロールすることができます。
アドレス可能な資産システム アドレッサブル・アセット・システムは、ゲームを構成するアセットの管理を簡素化します。シーン、Prefabs、テキストアセットなど、どんなアセットでもAddressableとしてマークし、ユニークな名前を付けることができます。そうすれば、どこからでもこのエイリアスを呼び出すことができる。
ゲームとアセットの間にこのような抽象化レベルを追加することで、別のダウンロード可能なコンテンツパックを作成するなど、特定の作業を効率化することができます。Addressableを使えば、ローカルであろうとリモートであろうと、アセットパックの参照も簡単になる。
パッケージマネージャからAddressablesパッケージをインストールします。プロジェクトの各アセットやプレハブは、結果として「アドレス可能」になる能力を持つ。
インスペクタ]のアセット名の下のオプションをオンにすると、そのアセットにデフォルトの一意のアドレスが割り当てられます。マークを付けると、対応するアセットが「ウィンドウ」→「アセット管理」→「Addressables」→「Groups 」ウィンドウに表示されます。
アセットが別の場所にホストされている場合でも、ローカルに保存されている場合でも、システムはAddressable Name文字列を使用してアセットを検索します。Addressable Prefabは、必要になるまでメモリにロードされず、使用されなくなると自動的に関連するアセットをアンロードします。このブログ記事「Addressableでメモリーを節約する」では、メモリーをより効率的に使用するために、Addressable Groupsをどのように整理できるかを紹介しています。
Addressablesを参照:コンセプトの紹介 アドレス対応アセットシステムがプロジェクトでどのように機能するかを簡単に説明します。
これまでで最も包括的なガイドの1つで、PCとコンソール向けにゲームを最適化する方法について、80以上の実用的なヒントを集めている。サクセスとアクセラレート・ソリューションズの専門エンジニアが作成したこれらの詳細なヒントは、Unityを最大限に活用し、ゲームのパフォーマンスを向上させるのに役立ちます。