Unityのゲーム開発における最適化について、最近私が行ったことの備忘録を残します。
対応させたプレイ環境
Quest3 スタンドアロンで遊ぶ、モバイルVRゲーム
プロファイラーの見方
まず、実機で処理負荷に問題のある箇所を見極めます。
次に、Unity Editorの Window > Analysis > Profiler でプロファイラを開いた後、ゲームを再生します。
処理負荷を確認したい箇所で一時停止し、詳細を確認していきます。
CPU Usage
- CPU Usageのグラフ部分をクリックすると、そのフレームで行われた処理が確認できる。
- 項目別に処理負荷を確認する場合、Hierarchy に設定する。
- 「Time ms」の値が大きいほど、その処理に時間がかかっている。
▲ 上の例では、Gfx.WaitForRenderThread の Semaphore.WaitForSignal に時間がかかっています。
メインスレッドがレンダースレッドを待機していることを示しています。
項目別の具体的な内容は、下記のリファレンスで確認できます。
Unity スクリプトリファレンス
https://docs.unity3d.com/ja/2019.4/Manual/ProfilerCPU.html
GPU Usage
GPUプロファイラは重いので、使わないときは閉じておいた方が良いようです。
Window右上の「Profiler Modules」から開閉できます。
- GPU Usageのグラフ部分をクリックすると、そのフレームで行われた処理が確認できる。
- 項目別に処理負荷を確認する場合、Hierarchy に設定する。
- 「GPU ms」の値が大きいほど、その処理に時間がかかっている。
▲ 上の例では、VFX.ParticleSystem.RenderMesh に時間がかかっています。
他にも沢山知っておきたい使い方があるので、下記記事で勉強させていただきました!
スパイクを軽減するための最適化
AudioClip の事前ロード
スパイクが起きている箇所の CPU Usage を見ると、SoundManager.GetHandle の SoundManager.LoadFMODSound が重く、AudioClipの読み込みにより負荷がかかっていることが確認できます。
複数の効果音やBGMを一挙にロードしていたので、AudioClipを事前にロードしておくように修正することでスパイクが解消しました。
● Scriptで保持するパターン (ロードのタイミング : 任意)
スパイクが起きているのとは別のタイミングで、AudioClip型変数に保持させておく。
● AucioClip側で設定するパターン (ロードのタイミング : 起動時)
事前にロードしておきたいAudioClipを開く。
AudioClipのPreload Audio DataをEnableに切り替える。
この対応の際に、AudioClipのLoadType も併せて見直しました。
短い音源(SEなど) は Decompress on Load、長い音源(BGMなど) は Compressed in Memory に設定しました。
Particle の事前ロード
画像のように描画負荷がスパイクの原因として疑われるケースで、そのフレームに初めて再生したParticleがある場合に試したい項目です。
私の試した状況では、スパイク時の実機(Quest3)でのFPSが 38 → 55 に改善したので、効果絶大でした。
● 状況
シーン上に元々Particleを配置してある。
再生したのは、このフレームが初めてだった。
● 対処
処理負荷がかかっても良いタイミングで、そのParticleの「初めての再生」を済ませておく。
↓例
// 画面暗転中など
private void Start()
{
_particle.Play();
_particle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
}
おわりに
最適化に関してもまだまだ勉強中なので、また経験値が増えた頃に書き留めたいと思います。
お疲れ様でした!