見出し画像

[Unity]アプリのパフォーマンス改善(5回目):総動員して細かく底上げ

先日、Android用ゲーム「マリンスクールシミュレーター」のプレビュー版をリリースしましたが、

AndroidはiPhoneにくらべて性能は低めで機種ごとのばらつきが著しく、
現状10-20fpsのカクカク状態の機種も多いようです。
テスト実機がPIxel3でなければチクショウ!
プレイしてくださった人からのフィードバックをもとに、パフォーマンスを改善するアップデートが続きます。
今までも苦しんでパフォーマンスを上げるためのあがきをしてきましたが、
果たして、何したらfps30以上にできるのか?
一体、どこまで苦しめば報われるのか?!

・画面の解像度を下げる

解像度が高いと描画処理は重くなるわけで、解像度を抑えます。
スマホでは何もしないと4kとか過剰な解像度にされかねないです。
Screen .SetResolutionというものをいじればいいようですが。
https://docs.unity3d.com/ScriptReference/Screen.SetResolution.html
1k解像度以下に下げても見た目が悪くなる割に効果は薄いようです。

・テクスチャの解像度を下げる

たいてい使用してるモデル。スプライトアセットのテクスチャの解像度は、高めに設定されてます。
すべての解像度を可能な限り下げます。
効果はかなり高いです。見た目気にならない限界まで下げます。
一括で解像度を変える事もできますが、グラにこだわるなら手動でやります。
アプリをPC版・WebGL版も出す想定なら、機種ごとに解像度を変えます。大量の画像をプラットフォームごとに解像度を変えるのは面倒ですが、絶対やるべきです。

・URPにする

URPにすると、標準シェーダーSRPよりセットパスコールが大幅に減り、軽くなります。ポストプロセスも仕様が変わり軽くなり、重そうなSSAOも軽々使えます。
そのかわり、影の表現(解像度)が大きく劣化します。マップが大きいほど粗くなります。

モバイルでは妥協して影なしにする判断もありです。まあオプションで影行事の切り替えを実装が最善策かと
PC用の時は影の解像度を上げれたらいいですが、プラットフォームを変えたときに影解像度が簡単に変えられるかは、未検証です。
参考記事
https://note.com/info_/n/nfef8f9424426

・LODアセットを実装する

LODはプレイヤーカメラとの距離に応じて表示するものを変える機能ですが、Unity純正のそれは性能が雑です。
こういうアセットを使います

LODを効かせたいものにアタッチすると、メッシュの表示を切り替える他に、距離でメッシュレンダラーは影表示オフ、スキンメッシュレンダラーならボーン変形1ボーン、ライト、オーディオならフェード、と半自動でできます。グループまとめて一括で処理すれば、大幅に高速化が見込めます。
このアセットはシーン上のすべてのLOD適用距離を一括で補正もできます。

安直に全オブジェクトをLOD化すると逆に遅くなるでしょう。グループわけして空オブジェクトにまとめて、それにだけアタッチするのが大事。

・マップをほどよく細切れにする

重いメッシュコライダー付きのメッシュと膨大な数のオブジェクトでできたステージを常時アクティブにするのは、大きな負荷です。
山の向こうの建物、建物の中の室内家具は近づくまで絶対見えないのだから、プレイヤーから見えない部分はばっさり非表示・非アクティブにすることで軽量化できます。
動かない全てのオブジェクトを大まかに10-100程度にブロック分けして(=親オブジェクトにまとめて)、距離と視界に応じて雑に表示を切り替えれば、大幅に負荷が減ります。
切り替えるには、Unity純正のオクルージョンカリングは無駄が大きく重いので、上記のOptimizersを使うのがいいですが、がんばれば自作でもいけるでしょう。シンプルな判定で一度に大量のオブジェクトをオフにするほど効果大です。
レンダラーを非表示にするだけよりも、オブジェクトごと非アクティブのほうがコライダーなど諸々な判定もなくなって軽くなりますが、表示し直すときにプチフリする可能性があり、見えないとこのオブジェクトがなくなれば当然、プレイヤー以外の動くもの=NPCにとっては問題のもとです。状況判断が必要になってきます。

・カメラ描画距離を設定する

カメラの描画距離はスクリプトでレイヤー別にセットできます。(インスペクターではできません)プロップや草は近距離のレイヤー、でかい建物は遠距離のレイヤーにセットすると無駄な描画が減り数フレーム向上します。

・レンダラーの影を非表示にする

ゲーム開始時に、シーン上のレンダラーをリストか配列に 全取得して、設定でいつでも影を切り変えられるようにします。数フレーム向上します
URPでは、レンダラーの影をオフにするコードはこんな感じです。

_Renderer[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;

なおゲーム開始後に生成・削除されるオブジェクトがあるなら、それも考慮する必要があります

・処理をインターバルにする

毎フレーム動作する必要のない処理は、可能な限りインターバルにします。
1秒に1回にすれば処理負荷が30~120分の1になるので、ものによりますが効果は大です。
インターバルタイマーは非常に単純ですが自力でコーディングすることになります。自作アセットならともかく、外部アセットをインターバルに改造しても不具合が出ないかは、状況次第です。

・見直し項目:メッシュ統合は適切か

MeshBakerなどのメッシュ・マテリアルを統合するアセットは、使い所を間違うと逆効果です。
使いまわしできない大きめなメッシュ・マテリアル・テクスチャをシーンに生成するので、当然メモリ・ファイル容量を圧迫します。
軽くするだけなら、上記のカリングのほうが圧倒的でメモリにも優しいです。
メッシュ・マテリアルを統合するアセットの有効な状況は限られていて、狭い場所にそこでしか使わない静的なオブジェクトが大量に密集してるときだけで、そんなもったいないアセットの使い方は、モバイルでするべきではないでしょう。 

・見直し項目:ビルボード使ってないか

モバイルでは透過テクスチャ=ビルボードの使用は大抵自殺行為です。
テレインの草とか、遠方のオブジェクトをビルボードにするアセットとか使ってないか確認します。
メニューのUIも透過画像で凝ると危険です。
透過テクスチャでセーフな状況は、どシンプルな形状、他の透過画像と重ならない、加算・乗算表示のシェーダーを使ってる、などです。

・見直し項目:カメラは一つだけか

演出などで複数のカメラを暫定的に使う場合、使わないカメラはしっかり非アクティブにします。URPではアクティブなカメラの数だけ露骨に重くなるようです。

・見直し項目:テキスト周りを疑う

テキストは、設定の言語切り替えやアイテムを拾ったなどの各種アナウンスなどで、かなりの頻度で書き換わるものです。
テキストを扱う処理は、場合によってはグラ描画より重いことがあります。
前回の記事で触れかけましたが、セールで買ったUI無限スクロールアセットを使ってUIのアイテムリストなどのテキストを書き換える改造したら、これがとんでもない失敗で、このアセットがたとえUIアセットが非アクティブでも常時処理し続けて止められないという仕様で、
ガベージコレクション=GCが超発生し、70fps出せるPC上でも20以下になる戦慄の結果になりました。
どうやったらGCを回避できるのかは具体的にはわからないのですが、
モーションのステート名とかタグとかアイテムインベントリとかキャラの会話とか多用してたら、毎フレーム走ってないか、文字の代入や参照を使わずにすませられないかを見直す…といいかもしれません。

そういうわけでマリンスクールシミュレーターをアップデートしました。
バージョン0.89です。少し軽くなってより多くの機種で遊べるようになりました。

ここまでやっても、他のスクールシミュレーターに比べてまったく重い。
有名所は広大なマップで40体以上のAIキャラをたやすくぶん回してるのに、こちらは20体でアップアップ…どんな魔法を使ってるんだろう。

この記事が気に入ったらサポートをしてみませんか?