(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

Profilerの使い方と最適化の目安の付け方(後編)【Unity】【Unite 2017 Tokyo】【最適化】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 2017.1.0f3


はじめに

今回は『Unite 2017 Tokyo』の講演の動画を見て、要点をまとめたり、追加で調べたり、

実際に手を動かしたりしながら、記事にもしちゃおうという感じの記事です。


そして、題材にする講演は、「最適化をする前に覚えておきたい技術」です!

講演者:黒河 優介(ユニティ・テクノロジーズ・ジャパン合同会社)

こんな人におすすめ
・最適化したいが、何をしてよいかわからず困っている人
・効率的に最適化を行いたい人


受講者が得られる知見
・Unity Profilerに関するノウハウ
・最適化の目算、見積もりをする技術


タイトル通り、この記事は後編で、いきなり常にフレームレート低い場合の最適化から始まります。

最適化とは、Profilerの基本的な使い方、メモリの使用量が多い場合の最適化

ロードが長い場合の最適化一瞬だけ画面が固まる場合場合の最適化

をご覧になりたい方は、以下の前編をご参照ください。



なお、記事中では以下のアセットを使っております。





常にフレームレート低い(処理が重い)場合

常にフレームレート低い場合(処理が重い)は以下のような手順で最適化を行なっていきます。


f:id:kan_kikuchi:20170904145036j:plain
【Unite 2017 Tokyo】最適化をする前に覚えておきたい技術 - YouTube


プロファイリング中はDebug.LogをOFFに

前編に触れましたが、Debug.Logは便利な反面、かなり重いです。

なのでプロファイリング中は無効にしましょう。

場合によってはこれだけ処理が軽くなります。


無効にするには以下のようにDebug.logger.logEnabled を falseにします。

Debug.logger.logEnabled = false;


もしくはDebugクラスを書き換えるという方法もあります。





描画が重い?ロジックが重い?

処理が重いとなった場合、描画が重いのか、ロジック(システム)が重いのかを判別する必要があります。


これを確認する際はProfilerのCPU Usageの部分を見ます。

Renderingという項目が多ければ描画が重く、それ以外が多ければロジックが重いといった具合です。

ただし、Vsyncという項目は次のフレームまでの待ち時間で、重さとは関係ないので無視しましょう。


f:id:kan_kikuchi:20170908192326j:plain


なお、PCとモバイルでは描画性能や解像度が大きく違うので

(最近のモバイルは解像度が極端に高い割に、描画性能はそれほどでもない)

上記の確認は必ず実機で行いましょう。


また、Screen.SetResolutionを使って解像度を下げたり、



CameraのViewport Rectを下げて描画範囲を狭くしたりして、


f:id:kan_kikuchi:20170908200803j:plain


描画処理を軽くする事で、描画が原因かどうか判定する方法もあります。


描画のチェック

描画側が重い場合は以下のような手順で最適化を行なっていきます。


f:id:kan_kikuchi:20170904145027j:plain
【Unite 2017 Tokyo】最適化をする前に覚えておきたい技術 - YouTube


余計な描画をしてないか?

そもそも余計な描画とは何かと言えば、表示されないのに描画をしている事です。

例えば、表示されている背景の裏に別の背景があったり、

誤ってCameraを2台設置してしまっていて、片方が無駄になっていたりという感じです。


余計な描画を確認する際はFrameDebuggerを使いましょう。

FrameDebuggerは描画の順序、描画したMaterialの確認などが出来ます。


使い方はWindow -> Frame Debuggerから開き、Enableを押すだけ。


f:id:kan_kikuchi:20170910133415j:plain
f:id:kan_kikuchi:20170910133426j:plain


そうするとUnityがどういう順序で描画しているかを確認出来るようになります。

これで余計なものがあれば取り除くという感じです。


f:id:kan_kikuchi:20170910134950g:plain


Batch数やSetPass数が多くないか?

そもそもBatch数やSetPass数とはなんぞやという所ですが、

Batch数(ドローコール)は描画の命令を呼んだ回数の事、

SetPass数はマテリアル切り替えの処理を呼んだ回数の事です。(Batch数 ≧ SetPass数)

どちらも多くなるほど処理が重くなり、モバイルでは200程度を目安にとの事。


なお、どちらともGameのStatsかProfilerのRenderingから確認できます。


f:id:kan_kikuchi:20170910135421j:plain
f:id:kan_kikuchi:20170910135429j:plain


これらを減らすには、

Textureをパッキングする事で同じMaterialを使用し、Dynamic Batchingが効くようにしたり、

動かないモデルをStaticにし、Static Batchingが効くようにしたりといった方法があります。


頂点数が多くないか?

頂点数(Verts)が多い場合も描画が重くなるので注意が必要です。

しかし、意外にも問題になる事は少ないようで、モバイルでも数万ポリゴンはいけるそうです。


なお、Batch数やSetPass数と同様、GameのStatsかProfilerのRenderingから確認できます。


f:id:kan_kikuchi:20170910140300j:plain
f:id:kan_kikuchi:20170910140309j:plain


描画面積が多すぎないか?

塗るピクセルが多いほど、描画は重くなりますが、

色が透明であっても同様に重くなります。(むしろ透明の方が重い)

なので、透明なUI等には注意が必要で、透明で何度も塗りつぶしているために重くなったりもします。


また、ImageEffectも付けすぎるとその分、描画が重くなるので注意が必要です。


Shaderが重くないか?

描画の負荷というのは描画面積 × Shaderの重さ(計算の複雑さ)によって決まります。

なので、描画面積の大きい所(地面や空)では軽いShaderを使いましょう。


なお、Shaderが重いかどうかをチェックするにはUnityのProfilerではなく、

各プラットフォームのProfilerを使った方が簡単で正確だそうです。


どうしてもUnityだけで調べたい場合は、描画面積の大きい分のShaderを

軽いShader(Mobile/Unlit/TextureやMobile/VertexLit等)に置き換えて確認するという方法があります。


ロジックのチェック

ロジック側が重い場合は以下のような手順で最適化を行なっていきます。


f:id:kan_kikuchi:20170904144939j:plain
【Unite 2017 Tokyo】最適化をする前に覚えておきたい技術 - YouTube


C#側が重い?Unity側が重い?

ロジックが重いとなった場合、

C#側の処理が重いのか、Unity側の処理が重いのかを判別する必要があります。


これを確認する際はProfilerのCPU Usageを選択した状態で下部の詳細を見ます。

Time msの項目をクリックして時間が掛かっている順にソートした時に

何が一番上にくるかを確認する感じです。


f:id:kan_kikuchi:20170908203307j:plain


上記のようにUpdateやLateUpateといったスクリプトに記述したメソッドが上位にある場合は、

C#側が原因ですので、プログラムを修正する必要があります。


Unity側のどこが重い?

時間が掛かっているのが、記述したメソッドでない場合はUnity側が重いという事になります。


例えば、Physics.Processing(2DならPhysics2D.Simulate)が

上位なら物理処理が重いという事になります。


f:id:kan_kikuchi:20170910112340j:plain


この場合、

MeshColliderをBoxCollider等に置き換えて、複雑な形での衝突判定をなくしたり、

Physices(2D)のLayer Collision Matrixを見直して、余計な衝突判定をしないようにしたり、


f:id:kan_kikuchi:20170910113747j:plain
f:id:kan_kikuchi:20170910113759j:plain


TimeのFixedTimeStepを増やして、物理計算の回数を減らしたりという事をする必要があります。


f:id:kan_kikuchi:20170910113823j:plain
f:id:kan_kikuchi:20170910113836j:plain


また、Canvas.SendWillRenderCanvasesが上位ならUI(uGUI)の処理が重いという事になります。


f:id:kan_kikuchi:20170910112353j:plain


uGUIが重いというのは、頂点処理の計算が重いという事なので、

なるべくCanvasは動かさず、動かしたい場合でも動くものを別のCanvasにしましょう。

(uGUIはCanvas内のなにかが変わると、全てを計算し直す仕様のため。)


それ以外にもGameObjectが大量にあるので重いという場合もあります。

ターゲットの端末にもよりますが、モバイルなら3000程度に抑えるようにしましよう。

なお、GameObjectの数はMemoryのGameObjects in Sceneで確認出来ます。


f:id:kan_kikuchi:20170910112441j:plain


Profilerの結果保存

最適化の話は以上で、ここからは+α的な話になります。


まず、Profilerの結果を保存や読み込みする方法ですが、

ProfilerのSaveやLoadから簡単に行えます。(Unity5.6以降)


f:id:kan_kikuchi:20170910143101j:plain


ただし、表示されている300フレームしか保存されません。

そこで、300フレーム毎に自動で保存していくれるエディタ拡張が以下のものです。



また、Unity5.5以前でもProfilerの結果を保存する方法が以下のものです。





スクリプトの特定部分だけで処理負荷を測る方法

通常だと、メソッド単位でしか負荷は表示されませんが、以下のように

ProfilerのBeginSampleとEndSampleで囲んだ部分だけの負荷を測る事が可能です。

//using UnityEngine.Profiling;が必要

Profiler.BeginSample("自由に名前が付けられます!(; ・`д・´)ナ、ナンダッテー!");
/*ここの負荷を測り、Profilerに表示*/
Profiler.EndSample();

f:id:kan_kikuchi:20170910143950j:plain


おわりに

初歩的な内容ではありますが、

かなり大事な内容ばかりなので、Unityを使い始めたばかりの時に見ておきたかった講演でした。


なお、実際の講演はより分かり易く、かつ、詳細な内容となっているので、

最適化?Profiler?という方はとりあえず一度視聴する事をオススメします!