Unity 高速化と負荷軽減
C#の高速化
Performance Tuning
CPU負荷
GetComponentの呼び出しを抑える(効果:大)
取得したインスタンスを変数にキャッシュして、呼び出しを最低限に抑えること。
Distanceやmagnitudeなど、距離やベクトルの長さの計算改善(効果:大)
必然性が無ければ、極力使わないほうがよい。
Animatorコンポーネント(効果:大)
少ないほど良い。単純にくるくる回ったりバウンドするだけのUIやアイテム系であれば、スクリプトで実装してUpdateを回した方が速い。
画面内に映らないUIの負荷(効果:大)
キャラクターの付近に表示するHPゲージや名前、照準などが該当。
3Dオブジェクトを追従して表示するようなUIの場合、画面外にいるときは描画もスクリプトも原則OFF
ObjectPool 頻繁に出たり消えたりするオブジェクトを都度生成しない
ダメージ数字やエフェクト、敵の攻撃の弾など、使いまわすようにしたり、必要なリソースをシーン開始時などにまとめてロードしておくことも重要
・Photonなどでリアルタイム通信をする場合は、出来る限り通信データ量を減らしたり、通信する処理をまとめたりしておく
ガベージコレクション(効果:中~大)
明示的に変数を解放せずGCに任せると、一定のタイミングでGCの処理負荷がかかり、FPSが落ちる。
インスタンスを扱うローカル変数の扱いにコーディングルールを決めて対策する
Animation付きのfbxのOptimize(効果:中~大)
特にキャラクターモデルのようにボーン数が多いものだと効果が大きい
参照が必要なものは、「Extra Transforms to Expose」で選択しておくこと
CanvasRaycasterの負荷(効果:中)
「Canvas Raycaster」が設定されているキャンバスの、UI要素数が多いほど、RaycastAllの処理(EventSystemを使っている以上避けられない処理)の負荷が大きくなる。
「Raycast Target」がtrueになっているUIを極力別のCanvasにまとめることで負荷を減らせる。
transformのposition、eulerAnglesへの代入改善(効果:小~中)
可能ならlocalPosition、localEulerAngles(rotation)への代入の方が軽い。
positionなどに代入すると、ローカル座標へ変換する処理が走るらしく、数が増えてくると地味に重くなる。
また、1フレーム内での計算で、transformへの代入が何度もあるとそれも無駄な負荷になるため、最終的な座標や角度のみをtransformに代入するように設計すること。
AnimatorのSetBool、SetTrigger(効果:小~中)
値の変化が変わらないのに、Update内で何度もSetメソッドを呼んでいると、無駄な負荷になる。
Set前に比較をして、変わらない場合はSetしない方が軽い。
これはAnimator以外にも、SetStateやSetActive、SetVisibleなどのいろんなSet系メソッドのことで言える。
ログの出力負荷(効果:小)
リリースビルドでDebug.Logを消してなければ消す
自身で入れているLog以外にも、Assetが大量にログを履いていたり、StarckTraceに格納?してたりする場合も
GPU Skinning(効果:小)
GPU負荷よりCPU負荷の方が高い場合に有効。SkinningをGPUに任せる設定をしている。
PlayerSettingsのOtherSettings内で指定可能。
GPU負荷
解像度を下げる
UIは解像度の変化による見栄えの劣化が目立ちやすい ので、おすすめはレンダーテクスチャーを使って3D空間を映した表示だけ解像度を下げる
カメラが映すものを低解像度に設定する
ライトを減らすorなくす
ライトの数が多ければ多いほど、GPU負荷は高くなります。
基本的に、特に陰影にこだわりがなければ
- Directional Light1つ
- 背景のShadowはライトマップをベイク
- 動くオブジェクトのShadowは丸影を使用(Projectorなど)
半透明のモデルを減らすorなくす
半透明のシェーダーは、処理が重くなりがち
描画順の管理が難しく、表示が破綻するバグの原因になる
極力半透明の表示になるモデルは少なくし、ディザリング による半透明表現が許容できる場合はこちらを使う
ドローコール(SetPassCall)を減らす
ドローコール数は、UnityのGameウィンドウで「Stats」を有効にすることで確認
一スマホゲームであれば100前後が理想
UI画像をテクスチャアトラスにする
原則、同時に表示する画像 はテクスチャアトラスにまとめる
UI画像をアトラス化するSpriteAtlas
マテリアル数を減らす
3Dモデルは、基本的に「メッシュ数 ✕ メッシュ毎のマテリアル数」の分だけドローコールを呼んでいます。シェーダーによっては、更に多いことも。
3Dモデルの設計を見直し、
- まとめられるメッシュは1つにする
- まとめられるマテリアル(テクスチャ)は1つにする
ことで、3Dモデルのドローコール数を抑えられます。
バッチングを働かせる
背景モデルなど、ゲーム中に動かないかつ他と同じマテリアルを共有している3Dモデル はstaticオブジェクトにすることでバッチングが働き、ドローコールの削減が期待できます。
描画のBatchingが有効になるように、マテリアルを極力まとめましょう。また、ゲーム中に動かさないものに関しては、かならずstaticオブジェクトにしておきましょう。
視界に同時に入ることが多いものは、1つのメッシュにまとめることも大事です。
staticオブジェクト以外でも条件を満たせばバッチングが働くため、ドローコールバッチング についてのマニュアルを読んでおくことを推奨します。
ドローコールについて、どういう表示がドローコールを呼んているか?何がバッチングされているか? については、Unityの Frame Debuggerで確認できます。
ドローコール数が高く、原因がつかめない場合はこちらを使ってチェックしていきましょう。
ポリゴン数を減らす
ポリゴン数が高いモデルはGPU負荷に影響します。
実際の端末サイズの画面+ゲーム内でのカメラ距離 で、アラが目立たない程度の適切なポリゴン数に抑えましょう。
画面内に映らないUIの負荷(効果:大)
キャラクターの付近に表示するHPゲージや名前、照準などが該当します。
3Dオブジェクトを追従して表示するようなUIの場合、画面外にいるときは描画もスクリプトも原則OFFにしておきたい です。
よく動くUIとそうでないUIを別なキャンバスにする(効果:中)
UIの位置や角度、スケールの更新は、Canvas単位 で行われるため、毎フレーム動くようなUI(マップのアイコンや、時間表示など)がほとんど動かないUIと同じCanvasにあると、動かないUI分も更新がかかり、無駄な描画負荷がかかります。
良く動くUIにCanvasコンポーネントをつけて、処理を分けることで改善が見込めます。
ただし、無暗にCanvasコンポーネントをつけるとそれはそれで重くなるので、Canvasの仕分け方は注意しましょう!
※Canvasコンポーネントは少ないに越したことはないです
LODモデル(効果:小~中)
距離によってモデルのポリゴン数などを上下させる仕組みです。
Unityのコンポーネント
3Dモデルの数が多く、カメラが遠くまで移すような仕様だと特に効果が大きいです。
ただし、ポリゴン数のレベル分クリエイティブが必要になる ため、効果が高いものにのみ適用することが望ましいです。
Unityでスマートフォン向けアプリを開発する上での負荷削減
Discussion