Unityパフォーマンス最適化のポイントメモ

【Unity道場16】パフォーマンス最適化のポイント に行ってきました。 その時のメモ ちょいちょい抜けてる所あるのでそこだけ注意

パフォーマンスの良いアプリ

パフォーマンス, 反応
CPU と GPU どっちをチューニングするべき -> 両方
どちらか片方でも時間かかった場合目標値にたどり着かないから

パフォーマンスはプラットフォームによって特性がある その特性に沿ったチューニングが必要

それぞれのCPU、GPU、メモリの参考

種類 CPU GPU MEM
スタンドアローン 潤沢 潤沢 潤沢
ゲーム機 物による 物による 物による
スマフォ 弱い
webGL 弱い 絶望
VR 弱い |

他要因 IOのアクセス メモリバンド

Unityエディタの特性はスタンドアローンに近い Unityエディタはアセットをキャッシュしまくる!

CPU、GPUの確認する方法は ー> とりあえずプロファイラを使う CPUとGPU時間が表示されるよ(単位はms)
より細かいのだと各プラットフォームに依存したプロファイラを利用したほうがよい

GPUについて

重くなる原因 - 重いシェーダ - フィルレート - オーバードロー - ハイポリ - 描画内容が多い - 画面外の描画 - ミップマップ未使用

解像度の高いデバイスでピクセルシェーダーは負荷が高い
pow exp log cos sin tan等の利用を避ける
normalize, dot, inversesqrt等を自前で記述は避ける
浮動小数点の精度を下げる

Unityはアルファ分を計算して最小限のポリゴンにしてフィルレートを下げてる
今まではハイポリでそこまで問題になってなかった、VRは2回描画するという特性で問題になってきた

表示するポリゴンを削減する方法
- LOD - OcculusionCulling

処理はCPUで行っている点に注意

ポリゴンを結合するアイディア (CPU負荷軽減) - オブジェクトを結合し、単一メッシュとして描画 - 欠点:カリングによってポリゴンが削減されない

影の描画負荷を減らす(GPU負荷軽減) - CastShadowsをOFFに - Received ShadowをOFFに

ローディングについて

不要なものはロードしない

アセットバンドルの場合は少し特殊
アセットバンドルに格納した場合、暗黙的に参照しているアセットを含めてしまう
シーンとアセットバンドルで同じアセットを参照した場合、それぞれは別の存在として認識される
アセットバンドルの依存関係の設計で重複ロードを避けるようにする必要がある

メモリが多いならロードしたアセットを破棄しないという方法もある

アセットバンドルの中にFBXを含んだ場合

ほしいのはアニメーション情報だが実際にデシリアライズするのはFBXの中身を行おうとする
FBXを読むのではなく、対象のアセットを参照するアセットを読む
プレハブなど必要なアセットを参照している場合はFBX全体をアセットバンドルに含まれるということはない

シーンで配置をして画面構築か ランタイムでの画面構築か

同じオブジェクトが1万個の並ぶ実態を作る場合
Create(Instantiate) Load(Scene) Clone(実態1つ作って)の中ならCloneが一番はやい
Createの中の処理だとadd componentが重い
Loadでは値の反映が一番重い パラメータの流し込む処理
スクリプタブルオブジェクトを利用することで改善をすることができる(デシリアライズが減る)

Clone処理が実験では一番早かったが、親子関係の構築するところで負荷が高い
GameObject.Instantiate(newGo, parentTransform)というAPIがある(5.4から)
alloc無しで親子関係が構築できる
parentTransform.hierarchyCapacity = 1000
GameObject生成・破棄のコストが安くなる
親の変更コストが上がる
InstantiateParentをした後に親子を変更すると負荷が高い

CPUに付いて

CPUの効率を求めるならCPUに働かせないこと!
けど、一切働かないのは無理 なので、バレないようにサボる

Culling Group - 部屋のレベルで処理のON/OFF - OnBecameVisible/OnBecameInvisible - 毎フレーム処理しない

CPU関連の一番の大きな問題 GameObject

ヒエラルキーの運用
UnityでGameObjectをフォルダ代わりに利用していることが多いが階層は作るのも動かす(座標だけ動かすだけ)のも負荷が高い
5.4でマシになった 5.6で早くなる
5.6になるまではGameObjectの階層には注意が必要

エディタの時だけ親子構築するなどの対策必要かも

じゃあAnimatorは? -> 回避策がある
FBXのインスペクターでRigタグでOptimize Game Objectを有効に オブジェクトの結合をする
手のボーンなど一部の座標が欲しい場合はExtra Transform to Exposeを利用 ただしリードオンリー
スキニングの処理負荷がガッツリ下がる
Animatorの場合Culling Groupを利用なくてもカリングができる
Culling ModeでCull Completelyに設定

非アクティブオブジェクトの扱い

有効な方法だが注意の必要な項目がある - Collider - Rigidbody2D - Canvas (ジオメトリ情報が破棄され、UIの再構築が走る 負荷が高い) - Animator

この3つはアクティブを切り替えると初期化される

対策
Canvas GameObjectのアクティブをするのではなく、Canvasをdisableにする
Animatorも同様 (初期化おきない)
Collider Rigidboyはどうしようもない
Rigidbody2DはSimulatedのチェックを外す

補足 Animatorのアクティブ切り替えの場合パラメータの流し込みの負荷が高い

UIについて

UIのバッチング UnityのUIは動かさない場合負荷がとても軽い
ただ 1つでも変化するとCanvas以下でオブジェクトの再構築が走る
変化するオブジェクトにCanvasを追加してやる
Canvas単位で再構築されるため

Fill Centerの無効

スクリプトのパフォーマンスの稼ぎ方)

効果の高い順に数字

1. local positionを使用する
2. VectorのOperatorを減らす
3. VectorのMathfを利用しない
4. transformをキャッシュする
5. engine codeの呼び出しを削減
6. Time.deltatimeをキャッシュする

Unity5.6でlocal position使用しない場合の負荷が軽減される

その他 - foreachを利用しない (5.5でコンパイラが変わったので効果がないかも) - ListではなくArray - NonAllocと名のつくAPIを使う - stringの結合を避ける - UpdateやLateUpdateのコールバックを避ける

おさらい - CPUとGPU両方共チューニングする - どの程度かはプラットフォームによって変わるy - CPUはシェーダーやポリゴンの設定を見直す - ローディングは余計なものはなくす - アニメーションhあオプティマイズを利用する - Transformの移動は控えめに - localPositionを使う - Vectorのオペレーションは避ける

Unity5.4くらいからマルチスレッドレンダリングが行えるようになった