[Unity]GPU負荷 備忘録

GPU負荷の原因はいろんな要素が原因に考えられます。
一般的にドローコールやモデルのポリゴン数を減らすことで負荷を下げていきますが、 **先にそもそもの設定を見直すことを推奨** します。
設定の難易度と効果を加味して、おすすめの対処順に紹介していきます。

 **1. 解像度を下げる
2. ライトを減らすorなくす
3. 半透明のモデルを減らすorなくす
4. ドローコール（SetPassCall）を減らす
5. ポリゴン数を減らす
6. その他** 

# 解像度を下げる
Android端末は、iOSに比べて **GPUが弱めの割に、解像度はやたら高い** ものが多いです。
綺麗な写メを高解像度で表示するのには優れていますが、常に画面を更新するゲームにとっては不都合な設計です。
対策として、表示解像度を落とすことでGPU負荷を抑えられます。

ただし、 **UIは解像度の変化による見栄えの劣化が目立ちやすい** ので、おすすめはレンダーテクスチャーを使って3D空間を映した表示だけ解像度を下げる手法です。
手前味噌で恐縮ですが、下記記事をご参考ください。

▼カメラが映すものを低解像度に設定する
https://qiita.com/flankids/items/cba8c66c122d56e397b1

# ライトを減らすorなくす
ライトの数が多ければ多いほど、GPU負荷は高くなります。
基本的に、特に陰影にこだわりがなければ

- Directional Light１つ
- 背景のShadowはライトマップをベイク
- 動くオブジェクトのShadowは丸影を使用（Projectorなど）

という構成を推奨します。

しかし、やはり **陰影のつけ方１つで画面のリッチさが大きく変わる** ため、どうしてもリアルタイムシャドウや複数のライトを使いたくなるかもしれません。その場合、下記のように対応するのがオススメです

**▼リアルタイムシャドウ**
広い範囲で影を表示すると解像度が荒くなるため、[Shadow Cascades](https://docs.unity3d.com/ja/540/Manual/DirLightShadows.html) を使いましょう。
なお、**デフォルトの設定だとモバイル端末ではShadow Cascadesが効かない** ため、 **GraphicsSettings** の Tier Settings で、iOS、Androidそれぞれの **Cascaded Shadows**
を有効にしておきましょう。

**▼複数のライト**
ライトが複数必要になるケースはの大半は、 **場所によって陰の付け方を変えたい** という理由だと思われます。
例）普段は斜め上からの月明かりのライトによって照らすが、街灯付近ではその光の影響を受けさせたい

この場合、ライトを複数用意せずとも [LightProve](https://docs.unity3d.com/jp/540/Manual/LightProbes.html) を使うことで実現でき、更にライトを複数用意するよりも処理が高速です。

# 半透明のモデルを減らすorなくす
半透明のシェーダーは、処理が重くなりがちです。（また、描画順の管理が難しく、表示が破綻するバグの原因になることも）
極力半透明の表示になるモデルは少なくし、[ディザリング](http://wordpress.notargs.com/blog/blog/2015/09/24/unity5破錠しない半透明描画を行う/) による半透明表現が許容できる場合はこちらを使うことを推奨します。


# ドローコール（SetPassCall）を減らす
ここまでの設定や表示物の見直しが済んだら、いよいよドローコール数の削減です。
ドローコール数は、UnityのGameウィンドウで「Stats」を有効にすることで確認できます。

一般的に、スマホゲームであれば、 **100前後に収めるのが理想だと言われています** が、最低保障スペックの端末を何に設定するか次第なので、最終的にはターゲット端末でFPSにどれくらい影響があるかで判断することになります。

ドローコール数を減らす主な方法は、以下のようなものがあります
 
## UI画像をテクスチャアトラスにする
ゲームの情報をわかりやすくするために、UIを増やしていくと、3Dモデルの表示よりもUIのオブジェクト数の方が多くなってしまいがちです。UIの画像が別々になっていると、一つ一つのためにドローコールが増えてしまいます。
原則、**同時に表示する画像** はテクスチャアトラスにまとめましょう。
Unity2017から、**SpriteAtlas** という機能が追加され、UI画像をアトラス化するのが非常にお手軽になりました。こちらを使ってまとめていきましょう。
参考：[Unity 2017の新しいスプライトをパッキングする仕組み、”SpriteAtlas”について](http://tsubakit1.hateblo.jp/entry/2017/05/04/233000)

## マテリアル数を減らす
3Dモデルは、基本的に「メッシュ数 ✕ メッシュ毎のマテリアル数」の分だけドローコールを呼んでいます。シェーダーによっては、更に多いことも。
3Dモデルの設計を見直し、

- まとめられるメッシュは１つにする
- まとめられるマテリアル（テクスチャ）は１つにする

ことで、3Dモデルのドローコール数を抑えられます。

## バッチングを働かせる
背景モデルなど、**ゲーム中に動かないかつ他と同じマテリアルを共有している3Dモデル** はstaticオブジェクトにすることでバッチングが働き、ドローコールの削減が期待できます。
描画のBatchingが有効になるように、マテリアルを極力まとめましょう。また、ゲーム中に動かさないものに関しては、かならずstaticオブジェクトにしておきましょう。
視界に同時に入ることが多いものは、１つのメッシュにまとめることも大事です。

staticオブジェクト以外でも条件を満たせばバッチングが働くため、[ドローコールバッチング](https://docs.unity3d.com/jp/540/Manual/DrawCallBatching.html) についてのマニュアルを読んでおくことを推奨します。

　
ドローコールについて、**どういう表示がドローコールを呼んているか？何がバッチングされているか？** については、Unityの [Frame Debugger](https://docs.unity3d.com/jp/540/Manual/FrameDebugger.html)で確認できます。
ドローコール数が高く、原因がつかめない場合はこちらを使ってチェックしていきましょう。


# ポリゴン数を減らす
ポリゴン数が高いモデルはGPU負荷に影響します。
**実際の端末サイズの画面＋ゲーム内でのカメラ距離** で、アラが目立たない程度の適切なポリゴン数に抑えましょう。

# その他

## 画面内に映らないUIの負荷（効果：大）
よくあるモノだと、キャラクターの付近に表示するHPゲージや名前、照準などが該当します。
3Dオブジェクトを追従して表示するようなUIの場合、**画面外にいるときは描画もスクリプトも原則OFFにしておきたい** です。

## LODモデル（効果：小～中）
距離によってモデルのポリゴン数などを上下させる仕組みです。
Unityのコンポーネントとして用意されています（[LODグループ](https://docs.unity3d.com/jp/540/Manual/class-LODGroup.html)）
3Dモデルの数が多く、カメラが遠くまで移すような仕様だと特に効果が大きいです。

ただし、**ポリゴン数のレベル分クリエイティブが必要になる** ため、効果が高いものにのみ適用することが望ましいです。

## よく動くUIとそうでないUIを別なキャンバスにする（効果：中）
UIの位置や角度、スケールの更新は、**Canvas単位** で行われるため、毎フレーム動くようなUI（マップのアイコンや、時間表示など）がほとんど動かないUIと同じCanvasにあると、**動かないUI分も更新がかかり、無駄な描画負荷がかかります。** 
良く動くUIにCanvasコンポーネントをつけて、処理を分けることで改善が見込めます。
ただし、無暗にCanvasコンポーネントをつけるとそれはそれで重くなるので、Canvasの仕分け方は注意しましょう！
※Canvasコンポーネントは少ないに越したことはないです

#### 参考
・[UIを動かす変形させるコストについて](http://tsubakit1.hateblo.jp/entry/2015/03/24/062102#UIを動かす変形させるコストについて)
・[UnityのUIが重いならCanvasを分割するといいかも](http://learnunityblog.blogspot.jp/2017/02/unityuicanvas.html)


描画負荷とゲームのクオリティは天秤に掛けられやすいので、まず出来る手をしっかり打っておくことが大切です！