Unite2012の講義内容をまとめました
元ネタは
『Performance Optimization Tips And Tricks For Unity』
Jonas Echterhoff & Kim Steen Riber
http://video.unity3d.com/video/6957357/unite-2012-performance
なのですが GPUの最適化に関しては、ほぼ ?にまとまっていました(ただし英語
http://docs.unity3d.com/Documentation/Manual/OptimizingGraphicsPerformance.html
シェーダ解説で一度解説したような気もするので 8月頃の記事を参照してください
忙しくて見れていなかったための自分用まとめですので すでに見た方はスルーしてください
『Unityのパフォーマンスの最適化 TIPSと方策』
●プロファイラを見てピークに注目!
●スクリプトの最適化
●プログラムのアルゴリズムの最適化101 (ここではすべてを解説しません)
●見えているオブジェクトに対してスクリプトを削ることができるかもしれません
OnBecameVisible,OnBecameInvisible を使用して callbackし無駄にスクリプトを使用しないようにします。
●毎フレーム必要のないUpdateを呼ぶよりも コルーチンを使用しましょう
//毎フレーム呼び出しvoid Update() {}
//0.2秒間隔での呼び出しIEnumrator Start() {while(true) {
yield return new WaitForSeconds (0.2f);
}
}
● UnityエンジンのAPIメソッドが毎フレームの呼び出しをする代わりに 結果を保持するように考慮してください
これは C#におけるゲッタープロパティに当てはまります
たとえば Transform.positionはグローバルPosition の階層を繰り返し呼び出します
■メモリーの最適化
●メモリの種類
Mono Memory
●Script Object
● Wrappers for
●Game Object
● Asetts
●Components
Garbage collected
Unity Internal Memory
●Asset data
●Textures,meshs,animation,etc。
●GameObjects
●Internals (Rendering,particles,physic,etc)
●Monoが割りつけたヒープブロック
●実行時に必要となったヒープサイズのブロックを追加する
●フラグメンテーション(メモリの分断)はメモリが消耗していないとしても新しく追加されたヒープブロックによって生じます
●ガベージコレクターがクリーンをおこうなうとき
ヒープブロックを利用可能なメモリのサイズに割付けられなかった時
System.GC.Collect() はガベージ・コレクタを明示的に動作させます が 処理不可が高いので実行は注意
class MyClass{public int a,b,c;
}
struct MyStruct{public int a,b,c;
}
void Update () { //Bad アロケートメモリがヒープメモリ上に発生し あとでガベージコレクトをすることになる MyClass.c = new MyClass(); // Good アロケートメモリはスタック上に発生し ガベージコレクションが発生しない MyStruuct s = new MyStruct();}
注意) この意味合いは 作業メモリの拡張方法なのですが ヒープメモリの場合はMONOが自由にメモリを管理して
割り付けることで内部的にはメモリ中の開いたところにバラバラに管理され 作業メモリへのインデックスを保持しています。使用後のメモリはガベージ(ごみ)となって残るために一定時間ごとに圧縮(ヒープソート圧縮)を行ってメモリを開放する必要があります。
それに対しスタックメモリはレジスタを使用してメモリを格納順に積み上げる(スタック)して使用後は最後に積んだメモリから開放します。そのため大規模なソートを行わないので遅延が発生しません。 一番近いイメージはJavaの配列やジェネリック関数のリスト構造でしょうか ちょっと違う?
●あなたのやり方でメモリマネージを実装する場合 再利用不能なクラス を割り付ける前にリストを使用してみてください
●オブジェクトプールの実例はアセットストアで『Astro Dude』を見つけてください
●インスタンス処理は重たいです
●オブジェクトの事前読み込みを使用しましょう
●再び登場させるオブジェクト(bullet、Explosionなど)GameObject を最適化する時にInstantiateとDestroyの代わりに
inactiveのリストにして保持します。
EX1はint型を何度も宣言していて メモリ効率が悪いで例です。
EX1)
Public class AnAllocatingWorker { class WorkData { public int value = 1;
}
WorkData CreateWorkData(){ return new WorkData();
}
void ProcessWorkData(WorkData data){ int[] TempWorkBuffer = new int[128*1024]; TempWorkBuffer[0] = data.value;
}
public void Update() {
ProcessWorkData(CreateWorkData());;
}
}
EX2)
Public class AnAllocatingWorker { class WorkData { public int value = 1;
}
WorkData CreateWorkData(){ return new WorkData();
}
int[] TempWorkBuffer = new int[128*1024];
void ProcessWorkData(WorkData data){ TempWorkBuffer[0] = data.value; }
public void Update() {
ProcessWorkData(CreateWorkData());;
}
●UnityのビルトインGUIシステムをゲームに使用しないでください ガベージコレクションと相性がよくありません
●ストリーミングしないゲームではいつもゲーム中にアロケーションが発生するわけではありません
●GetRuntimeMemorySize(Object) を使用します。 GetMonoHeapSize と GetMonoUseSize を使用してメモリ使用量を追跡します。
●メッシュコライダーよりもプりミティブなコライダーのほうが最適化に良好です
●Time.fixedDeltaTime (project settings ->Time) の設定をします。おそらくゆっくり動くゲームの時はfixedUpdatesよりも良い結果をもたらします
●最も一般的なパフォーマンス低下の落とし穴はphysicsです
●けして動くことのない静止したコライダー(例えば リジッドボディを伴わないコライダー)
●プロファイラーで『Static Collide.Move』で表示されるものですが プロセスは物理演算を行なっています
●GPUとCPUの限界までスピードをあげられるのか
●GPUのパフォーマンスはレンダリングされるピクセルの最大数とメモリの帯域幅で決定されます(フィルレート)
●CPUのパフォーマンスは ドローコール処理の上限にしばられることがあります
●GPUプロファイラはドローコールあたりの消費時間を見つけることに役立ちます
●ドローコールを解消することでGPUとCPU両方のレンダリング処理が軽減されます。最初にできる限りのドローコールを削減してみましょう
●その結果 オブジェクトを高速にレンダリングするにはどうすればいいいかを知ることができます
●少数のオブジェクトでレンダリングすることでパフォーマンスは改善します
●シーンを簡略化する
●積極的にカリング(オクルージョンかリング、円錐台カリング)を使用する
●LODを使用する
注意)現在主流のGPUでは1ピクセル中にあまりに多くのポリゴンが集中すると処理落ちが発生するようです。そこで積極的にLOD
(少ないポリゴンのモデルを段階ごとに持つ)をすることでカメラから遠距離にポリゴン数の多いモデルが表示されないようにす る必要があるようです。
●パフォーマンス改善のためにシェーダーパスを削減します
●シーンセットアップ時にパスの少ないシェーダーを選択する(リフレクション。シャドー。ピクセルライトはフォワードレンダリングにおいてすべてのパスが加算されます)
●フォワードレンダーのピクセルライトは低速です。可能なかぎりリアルタイムライティングを避けてライトマッピングを使用しましょう
●ピクセルライトの数をクオリティセッティングで調節します。
●CPUパフォーマンスはドローコール処理の上限に影響されます
●注意:現在のハードウェアではフレームあたりのドローコールはモバイルで数百、デスクトップで数千を超えないようにしてください。
●ドローコールを減らすために 近接するオブジェクトはひとつのメッシュにまとめ 一緒に描画されるようにします。
●手動ではソースアセットの管理
●自動ではUnityのドローコールバッチを使用します → ドローコールバッチのリファレンス
「dynamic batching」について。unity3dfan @ ウィキ http://www38.atwiki.jp/unity3dfan/pages/42.html
注意)Unityは自動で900頂点(UV保持時は300頂点)までのポリゴンを自動でひとまとめに処理するダイナミックバッチと呼ばれる機能が搭載されていまあす。 マテリアルとテクスチャはひとつにまとめておくことが条件です。 ほかにスタティックバッチ インスペクタの右上のstaticのチェックをいれることで機能するものもあります。これは背景などの静止物に主に使用します。
●メッシュの中に含まれる異なるマテリアルはなるべく少なくしてください
●可能ならばテクスチャのアトラス化をしてください 注(アトラス化 複数のテクスチャを一枚のテクスチャにまとめること)
●多くのオブジェクトが複数のライトの影響を受けているとか 効率良くカリングを行わないとドローコールバッチはパフォーマンスを悪化させてしまいます
●GPUのパフォーマンスはレンダリングされるピクセルの最大数とメモリの帯域幅で決定されます(フィルレート)
●フィルレートの限界を知ることは簡単です。高速にゲームを動かした時ディスプレイ解像度が減少しますか? もしそうなるならそれがフィルレートの限界です
●同様に、クオリティセッティングでテクスチャクオリティを下げてみます。ゲームをが早くなるときは そこがおそらくメモリの帯域限界です。
●フィルレートが限界ならば最適化としてシェーダーを簡略化してみましょう
●モバイルのGPUの時:アルファテストを除外します。
●簡潔で整理されたシェーダコードをつかいましょう(たとえばUnityに付属の『Mobile』シェーダーのような)
●シェーダーコードの最適化:
● 効率の悪い関数を避けます(pow,exp,log,cos,sin,tan,など)。テクスチャ行列の事前計算も考慮してみます
●モバイルの場合:可能な限り低精度の変数を使用する(Cgにおけるfloat,half,fixed)
●もしメモリ帯域の限界ならばテクスチャメモリを減少させます
●テクスチャ圧縮を16ビットに
●テクスチャサイズを縮小(シーンビューンのレンダーモードのミップマップのチェック)
●テクスチャにミップマップを設定する。
●複雑なジオメトリによってもGPUのパフォーマンス限界はもたらされます
●必要以上のポリゴントライアングルは使用しない
●UV継ぎ目とハードエッジ(頂点に複数の法線)は可能な限り減らす
●シンプルなシェーダーを使用しましょう
■最適化に関する下記の項目も参照してみてください
Modeling Characters for Optimal Performance
※2014 8.16 >うにばな 講座みたいなもの番外編(高速化(最適化)について3 モバイル系 投稿しました よろしければ参考にどうぞ
