序文
この記事では、主に私が実際の仕事や勉強で使用した最適化手法を皆さんの参考や勉強のために共有するとともに、知識を定着させるために自分用の記録やまとめも兼ねています。
実際、最適化はいくつかの主要なレベル、つまり私たちがよく知っている 3 つのコアから開始することに他なりません。CPU、メモリ、GPU。それは私たちが最も接触しており、最も理解する必要があるものでなければなりません。以下ではこれら 3 つの側面について説明します。
記事ディレクトリ
CPUの最適化
1. CPU自体
まずCPUは何でできているのでしょうか?ざっくりまとめると、コントローラー、演算器、レジスタ、キャッシュ、バスです。特にすべてを理解する必要はありませんが、主にキャッシュとレジスタに注目します。
レジスタ (Register) は、CPU 内の非常に小さく、非常に高速な記憶装置です。レジスタは CPU に近く、メモリよりも高速ですが、サイズは小さく、通常、関数の戻り値 (int char bool など) や数学演算の結果などの小さな一時データを保存するために使用されます。 。
したがって、CPU を最適化するには、まずどこに CPU が必要かを理解する必要があります。CPU の仕事の責任は多すぎますし、範囲も広すぎます。出会いの一部を列挙することしかできません
2. CPU最適化記録
GCの最適化
GC - ガベージ コレクション メカニズム。GC が主にメモリ上で動作するのは当然ですが、なぜ CPU 最適化が行われるのでしょうか? 実際、これは非常に単純で、GC は本質的にマネージド ヒープ内のオブジェクトをクリーンアップすること、つまりマーク-クリア-圧縮です。具体的な実装については、Boehm GCやS-GenGCなどの関連アルゴリズムを参照してください。
実際、これらのアルゴリズムは、オブジェクトとオブジェクトの間の参照を見つけるためにトラバースすることによってオブジェクトをクリアできるかどうかをマークします。したがって、マネージド ヒープ内のオブジェクトが増えると、1 回の GC リサイクルのコストが高くなります。GC 自体のリサイクルも CPU によって処理されるため、GC は実際には CPU と密接な関係があります。
- クラスが比較的単純な場合は、構造置換の使用を検討してください。より高い効率。
- CPUのキャッシュヒット率を向上させ、メモリの連続性の確保を図ります。
- 頻度の高いNew Class/Container/ArrayなどはUpdate時のボックス化操作を極力避け、ローカル変数に可能な限りキャッシュする必要があります。
- 匿名関数とデリゲートは注意して使用する必要があります。メソッドをパラメータとして渡すとき、それが定義されたメソッドの場合、ヒープ メモリの割り当てが行われます。匿名関数の場合、非クロージャのみが追加の GC を生成しません。
- 多目的オブジェクトプール
- List の ToArray メソッドは使用しないでください。これはコピー用の配列の新しいコピーであり、さらに多くの GC があるためです。
- yield return 0;//ガベージが生成され、int 変数 0 がボックス化されます。yield return null に変更します
- 適切なタイミングで GC.collect を積極的に呼び出します。
- Linq と正規表現には、バックグラウンドでガベージを生成するボックス化操作があるため、慎重に使用するのが最善です。
- 文字列を扱うときは、文字列自体は定数であり、作成後に変更することはできないことを理解する必要があります。その値を変更すると、実際にはコピーとなり、追加の GC が発生します。Update では、割り当てや結合などの文字列の操作を避けるようにしてください。ステッチは可能な限り StringBuilder で行う必要があります。内部的には、Char 配列として実装されます。
コード効率の最適化
- キャッシュ: 時間のためのスペース。頻繁に使用されるオブジェクトをキャッシュしてみます。
- 前処理: 同時に処理するデータが多すぎることによる過剰な CPU 使用率を避けるために、計算を同時に進めます。
- フレーム制限方式: Buff モジュールなど、一部のモジュールがフレームごとにリフレッシュを処理する必要がない場合。Tick を 1 秒ごとに 1 回、または 0.5 秒ごとに 1 回最適化できます。
- フレーミング方法: たとえば、モンスターを生成する場合、1 つの世代を複数のフレームに割り当てて、同じフレームのオーバーヘッドを削減できます。
- マルチスレッド: ネットワーク モジュールおよびファイル読み取りおよび書き込みモジュールでは、CPU 効率を最適化するためにマルチスレッドを考慮できます。
- イベントメカニズム: Tick による判定が必要な一部のロジックをイベントメカニズムトリガーに変更できます。フレームごとに判定する必要はありません。
DrawCallを減らす
DrawCall は実際にはレンダリング コマンド、つまりグラフィックス レンダリングを呼び出すためのインターフェイスです。この処理は主にCPUが担当します。DrawCall の削減は本質的に、より多くのデバッチ処理、つまり、より多くの頂点データが一度にマージされ、送信されます。
- 静的バッチ処理、CPU 用のメモリ。正確に言うと、DC を減らすのではなく、バッチを結合することです。つまり、レンダリング ステートを 1 回設定するだけで済み、DC は変更されません。メリットは明らかで、1つはBatchの削減、もう1つはCPUの計算量の削減ですが、アート制作段階でマージするとUnityはサブモデルの可視性を判断できなくなります。これにより、CPUの演算量が増加する。もちろん、欠点もあります。つまり、ゲームオブジェクトが共有モデルを参照する場合、静的バッチ処理が実行されるとグリッド データの複数のコピーがコピーされ、同じモデルを参照するシーン内のすべてのゲームオブジェクトがモデルの頂点情報をコピーする必要があります。計算後に最終値に変更し、ワールド空間で結果の頂点バッファに格納されます。これにより、パッケージのサイズが増加し、実行時のメモリ使用量が増加します。
- 動的バッチ処理: 頂点属性の数ではなく、900 個の制限があることに注意してください。法線ベクトル、UV、接線を含める必要があり、合計数が 900 を超えてはなりません。これはランタイム処理であり、必然的に CPU 消費量が増加します。
- GPUインスタンス化
メモリ最適化レコード
私たちの主な関心事は、ネイティブ メモリとモノラル メモリです。簡単に言えば、1 つは Unity リソースが保存される場所であり、もう 1 つはコードが適用される場所です。
リソースの最適化
1. テクスチャー
- 圧縮形式:
- テクスチャ サイズはできる限り小さくする必要があり、2 の N 乗になるようにしてください。
- 要件に従ってミップマップを有効にするかどうかを決定します。UI をオンにする必要はありません。
- テクスチャを動的に操作する必要がない限り、読み取り/書き込みを有効にしないでください。
- アトラスの問題: たとえば、アトラスの使用率などを考慮して、複数の小さな画像に分割することをお勧めします。
2. グリッド
-
頂点の数は多すぎてはならず、静的バッチ処理の上限を超えないようにしてください。
-
PlayerSetting > OtherSetting > Optimization > Vertex Compression をオンにすると、頂点データの精度が 32 ビットから 16 ビットに低下する可能性があります。同じオプションにはメッシュ データの最適化もあります。これをオンにすると、法線、接線など、使用されていない頂点データを削除できます。現時点ではバグがあるようです、テスト使用です。
-
モデルのインポート設定には、メッシュの最適化もあります。原則は、実行時のレンダリング効率を最適化するために頂点インデックスを再配置することです。
-
読み取り/書き込み可能はテクスチャと同じです。必要な場合以外は開かないでください。
-
頂点の結合: 頂点を結合します。開くことをお勧めします。オーバーヘッドを減らすために、同じ位置でいくつかの頂点をマージできます。
-
Normals&Tangents: モデルが使用されていない場合は、法線接線をインポートしないことを選択できます。
-
モデルの分割も非常に重要であり、粒度は大きすぎても小さすぎてもいけません。大きすぎると錐台が取れやすくなります。
-
モデルの頂点とフェイス アートを変更できない場合は、CombineInstance クラスの CombineMeshes メソッドを使用して、いくつかのメッシュを手動で結合することを検討できます。もちろん、テクスチャが異なる場合は、テクスチャをマージする必要があります。UV をリセットします。
3. アニメーション
- スケルトンのインポート設定 OptimizeGameObjects をチェックすると、Transform のみを持ついくつかのボーン ノードを削除できます。CPU効率の向上
- Animator.Initialize のトリガー頻度を制御します。頻繁にインスタンス化されるアニメーション キャラクターの場合は、バッファ プールを使用して処理することをお勧めします。アニメーション キャラクターを非表示にする必要がある場合は、キャラクターのゲームオブジェクトを直接非アクティブ化しないでください。ただし、Animator コンポーネントを Disable にし、GameObject を Offscreen に移動することで、Animator.Initialize の呼び出しの頻度が減ります。
- Animator—CullingMode は、Cull Update Transforms に設定できます。オブジェクトがカメラに表示されていない場合は、ルート ノードの変位注入のみを計算してオブジェクトの正しい位置を確認します。または、Cull Completely : オブジェクトが表示されていない場合は、Cull Completely に設定できます。カメラによって、実行中のアニメーションが完全に終了します。
- アニメーション データの精度を下げるため、デフォルトのキーフレーム データは float に格納されます。一般的な実装アイデアは、Anim ファイル自体のデータを読み取り、曲線内の値を変更し、精度を 3 桁に下げることです。
- スケーリング カーブなど、最初から最後まで変化しない一部のカーブなど、冗長なカーブを削除することもできます。メモリ使用量を最適化します。
- 一度にレンダリングされる同様のオブジェクトが多数ある場合は、GPU スキニング + GPU インスタンス化の使用を検討してください。つまり、アニメーション データをテクスチャにベイクし、頂点モーションを GPU に渡して処理します。
4. フォント
フォントトリミングツールを使用して、珍しい文字などを切り取ってサイズを小さくすることができます。
5、アセットバンドル
この部分は主に、ロードされた AB パッケージとアセットが適切に処理される場合のマクロ リソース管理に関するものです。
- 参照カウント: AB の資産の参照カウントは、カウントによって記録されます。
モノラルメモリの最適化
この部分の最適化は上記の GC の最適化と似ており、本質も似ており、ヒープメモリの割り当てを減らすことで GC トリガーの頻度をある程度減らすことになります。
- オブジェクト プール: 頻繁にインスタンス化および破棄されるオブジェクトの場合は、オブジェクト プールを使用して管理するようにしてください。インスタンス化の消費量を削減し、メモリを再利用します。
- GC.Collect を積極的に呼び出して、ガベージを積極的に収集することを検討してください。
レンダリングの最適化
UGUIの最適化
UGUI の最適化には複雑なものがたくさんありますが、実際には原理は似ています。つまり、より多くのグリッド バッチを確保する方法と、頻繁な再構築を減らす方法です。
- アトラス、アトラス戦略は非常に重要です。大規模な UI 機能ですべてのテクスチャを確保することが最善です。をアトラスに入力すると、いくつかの一般的な UI テクスチャが一般的なアトラスに入力されます。大きな UI では同時に 2 つのアトラスのみを使用するようにしてください。
- アトラスの利用上の問題: アトラスに多くの空白がある場合は、一部のテクスチャの透明な領域をカットするか、長いテクスチャを 2 つにカットすることを検討してください。
- 静的と動的を分離して、頻繁に移動する UI 要素によってキャンバス全体での再構築が頻繁に発生するのを防ぎます。
- Image コンポーネントの空の Sprite をクリック イベントを受信する必要がある場合は、EmptyRayCast を使用して描画頂点データの送信を削除します。
- UI オブジェクトの Z 値に注意してください。0 でない場合、バッチ処理が中断される可能性があります。
- マテリアルの問題に注意してください。UI デフォルト マテリアルを使用しない場合は、バッチ処理が中断されるため、UI が重なりすぎないように注意してください。
- マスクマスク。代わりに RectMask2D を使用してみてください。Mask はテンプレート バッファーを使用し、クリッピング用に 2 つのdrawCalls と RectMask2D を追加します。
- UI インターフェイスの階層構造は、複雑すぎずに単純化するようにしてください。再バッチでは深度トラバースを計算する必要があります。
GPUの最適化
- 画面の数は多すぎてはなりません。
- LOD。
- シェーダ内の変数データ形式は削減され、たとえば半分が Float に使用されます。
- カメラはオクルージョン カリングをオンにし、シーン オブジェクトもそれを忘れずにチェックします。
- 軽いベーキング
- 透明なオブジェクトには注意してください。不透明なオブジェクトは透明なレンダリング キューに入れるべきではありません。
- テクスチャ解像度の制御。俯瞰ビューの 3D ゲームの場合、帯域幅を節約するためにテクスチャ解像度を適切に下げることができます。
- 可能であれば、影を単純なテクスチャに置き換える必要があります。
- Fog {Mode Off } フォグ効果をオフにします