講座みたいなもの番外編です。
今回は "Unity3D 高速化" という検索ワードが非常に多かったため 公式サイトなどで確認した手法を
まとめてみます。


■『使用頻度の低いファンクションは削る』

■『FindObjectsOfType, FindGameObjectWithTag, GameObject.Find といったFind系は処理が重い』 出来る限りAwake()、Start()文中などの初期化段階で行いましょう

■『static型を使用してください』静的な変数であるStaticタイプを使用することでメモリは固定され処理効率があがります。 これちょっと訳が正確かわかりません 単純に静的な値の割付け(つまりキャストしなさい)ということかもしれません。 



最近のハードウェアでのフレームあたりのドローコールは500回程度ですが あまり多いポリゴン数とライトの数は処理を低下させます 
対策として

■『モデルをコンバインする』 MeshMergerなどを使用して シーン内のメッシュをまとめてしまいます。
まとめるモデルは なるべく同じマテリアルを使用していて 一枚のテクスチャがはられていることが好ましいです。
これはモデル数が多いとCPUの計算コストがあがりGPUに対して複数オブジェクトを何度もレンダリングコールすると
処理負荷が高いということに基づきます。

■『ライティングはライトマップに焼き付ける』これは3.0以降はビーストライトマップが使用できます。もちろん3Dソフトでライトマップを焼き付けるのも可能です。
 
■『ライトはカリングマスクを使用して必要以上のオブジェクトに照射しない』 レイヤーでカリングマスクを使用することでライトがどのオブジェクトにあたるかを指定することができます。必要以上のライティングは行わないようにするほうが高速です。

■『レイキャストは低速なのでを使用するときはかならずカリングマスクをして必要以外のオブジェクトは対象から外す』  これもやはりレイヤーマスクを使用して レイの判定に必要のないオブジェクトは除外します。

■『配列を使うときは静的な配列を使用する』 これはおそらく 配列の指定で 単にvar=Array(); とするより

var[100」などと配列の個数を静的に割り当ててしまったほうがメモリ効率が良いということだと思われます。
■『OnEnable、OnDisable を使用する』カメラに写っていないオブジェクトの処理をしないようにする 

■『カメラから遠くに存在するようなオブジェクトはUpdate()文中でReturnをする』

■『トリガーを使用してプレーヤーが接近した場合にのみ処理するようにする』 

■『coroutineを使用してUpdateを5秒間隔で行う』 例には5秒間隔と書かれているのですが ようするにYieldを使用してコルーチンにディレイを掛けるということだと思います。 たとえば敵のサーチなどの処理は毎フレーム行わなくても良い処理ですのでUpdate文のなかに書かずに コルーチン化して数秒に一回呼んでやるようにすれば処理が軽くなるということです

■『Math関数のサイクル数の目安』
• Add, subtract, multiplyは同程度のサイクル数
• Divide: 30-40 サイクル
• Square root, sin, cos: 60-100 サイクル

■『ループ内での Sqrt と Normalizeの使用を避ける』
Nomalizeは内部にSqrtを含むため
• if (distance > dif.magnitude)
• if (distance * distance > dif.sqrMagnitude)
などは重たいのでしない

■『Cacheを活用する』

例:
private var myTransform : Transform;
function Awake () {
myTransform = transform;
}


■『JavaScriptに関して』
Static typing をすればC#と同様の速度が得られるらしい 
つまり 型のキャストをしっかり手動で行う。
UnityのJavaはC++の50%程度のスピードで動く これはMozillaの20倍の速度
スクリプト内で#pragma strictを宣言すると 動的な変数割付に対してエラーが帰るので参考にして調整する




とここまでが公式の資料によるものです。

ここから下がリファレンスのオプティマイズに関しての記述の解説です。





■キャラクターデータの高速化

『キャラクタモデルには1つのスキンメッシュレンダラーで構成する』
『マテリアル数は可能な限り多く無いほうがいい シェーダー負荷が高いためで 例えば銃などマテリアルを分けなければならない場合は別モデルにすること』
『可能なかぎりボーン数は減らす 通常のゲームで15-60のボーン数 モバイルマシンなどでは30程度が適切な数値』
『ポリゴン数の目安 300-1500がモバイル 500-6000がデスクトップ
Half Life 2 のキャラクターで 2500-5000 , PS3 or Xbox 360 でだいたい 5000-7000 ぐらいが適当。』
『インバースキネマティックはFKにベイクしておく』
『未使用のリグは消しておく』
『正しく骨を命名してください』



■スクリプトの高速化
前の記述とダブるところがありますので注意して読んでください。

1. Use Static Typing

変数の型を静的に割付け つまり使用するときにきちんと宣言すること
宣言しなくても自動で判別して実行してくれるのですが その分処理がかかります

例:
function Start () {
var foo = GetComponent(MyScript);
foo.DoSomething();
}

  
       ↓ このようにする
      
function Start () {
var foo : MyScript = GetComponent(MyScript);
foo.DoSomething();
}



2. Use #pragma strict
『#pragma strict』を宣言して動的宣言しているところのエラーが返るようにして静的宣言に調整する
ただしですが どうしてもコンパイルエラーが返る場合があるので そういう場合は『#pragma strict』はずしてコンパイラに任せたほうがいいです
特にGetComponent()を使用して値を参照するときのエラーが消えないことが多いようです。

例:
#pragma strict
function Start () {
var foo : MyScript = GetComponent(MyScript) as MyScript;
foo.DoSomething();
}



3. コンポーネントの値のキャッシュ使用

transformをmyTransformと自分が用意した変数で定義します

例:
private var myTransform : Transform;
function Awake () {
myTransform = transform;
}

function Update () {
myTransform.Translate(0, 0, 5);
}


4. Use Builtin arrays
配列はあらかじめ使用する配列の個数を指定してしまうことで効率よくメモリ使用されるようです

例:
private var positions : Vector3[];
function Awake () {
positions = new Vector3[100];
for (var i = 0; i < 100; i++)
positions[i] = Vector3.zero;
}


5. 必要のないUpdateコールは避けましょう。

Update ()文は毎フレームコールされるので できれば必要ない条件でreturn;をはさんで何もさせない処理をするといいです
例はターゲットから遠い時に何もしないよう設定しています
またOnBecameVisible()、OnBecameInvisible ()でカメラに映っているときに処理をするように
指定します

例:

var target : Transform;

function Update () {
// Early out if the player is too far away.
if (Vector3.Distance(transform.position, target.position) > 100)
return;
// perform real work work...
}



例:

function OnBecameVisible () {
enabled = true;
}

function OnBecameInvisible () {
enabled = false;
}



2.トリガを使用するときには一番軽い球型(sphere)のコライダを使用すると高速です。
球の公式を見ればわかるのですが オブジェクトの接する判定はトリガ中心とオブジェクトの距離の判定だけです。
ボックスの場合は6面分の接触判定の計算になりますし カプセルの場合は縦横比分の計算コストがかかります。メッシュコライダはもちろん重いです。
3Dゲームの場合たいてい高速処理のために球型のコリジョンで判定します。 四角い場合などはオブジェクトの形に合わせて小さな球コリジョンをいくつか
並べるなどのやり方もあります。 もっとも最近のハードは高速ですので昔のようなこの手法は特別に処理軽減を狙わなければあまり必要ないと思われます。

例:

function OnTriggerEnter (c : Collider) {
if (c.CompareTag("Player"))
enabled = true;
}

function OnTriggerExit (c : Collider) {
if (c.CompareTag("Player"))
enabled = false;
}



■補足
このほかに有効そうな手法を記述します。

『ウェイトの影響範囲を2本以下に』これは プロジェクトのクオリティ設定でできます
『テクスチャの大きさを調整する』Unityのテクスチャの設定項目でサイズを変更できる箇所がありますので FPSを調べて重たい箇所のテクスチャサイズを小さくします
『シェーダーのパス数に注意 シェーダーはあまり重くしない』 シェーダーのソースをひらくとPASS:という箇所があると思いますが これがレンダラーのコール部分なのでこのPASSの合計数があまり多くなりすぎないようにシェーダーを選択します。
『LODモデルの切り替え』
これは前回の記事で解説しました。予めポリゴン数やテクスチャの小さな複数モデルを用意しておきカメラからの
距離に応じて切り替えることで高速化を期待する技術です。
背景には3.0から搭載されたオクルージョンカリングがありますがこれは カメラからの距離や画角などである程度ポリゴンを非表示にして処理軽減をしてくれる技術ですが、遠くから近づいてくるポリゴン数の大きなモデルなどは突然現れてしまうため見かけが悪い場合があります。 複雑なモデルデータはポリゴン数を減らしたモデルを切り替え表示したほうが良いかもしれません。
昔のはなしですが例えばレースゲームの背景でコーナー付近はポリゴン数が非常に多いため何段階かのLODをもつことがありました
ただあまり多くのオブジェクトに設定すると処理が逆に大きく掛かるので限定した方がいいと思います。

『ライトマップをつかう』 よくやりがちなのがシーン全体をテクスチャベイクしてしまうことですライティング情報として影などをテクスチャとして焼きこんでしまうわけですが当然テクスチャサイズが大きくシーン全体をカバーするには量も膨大になります。
テクスチャはタイリングをうまく活用し それほど解像度の大きくない内蔵のライトマップを使用すればこれは回避できます。 

『パーティクルは内蔵のものを使用する』 大量のアニメーションデータベタもちは当然重いです どうしてもやるならモデル的にマージして切り替えアニメにするほうがいいでしょう。
内蔵パーティクルはビルボード処理やソート処理などもしてくれますので やはり内蔵のものを使用するのがいいと思います。スクリプトで制御できる上にあまり重たくなくて性能的にはかなりいいです

これらをGameウィンドウのStats あるいはProfilerを見ながら調整を繰り返します。




この他に いまのところスタンドアローン版にはC++やObjective_CなどでDLLやプラグインを使うことが可能なようです(プロ版)
それがどのくらいの効果があるかは まだ試していないのでわかりませんが、将来的にはPS3やXBOXなどの
家庭用ゲームのプラットフォームにも拡張されると思います。
処理が必要な部分に局所的に使用すれば効果は高いのではないでしょうか


後述:

先日の某所のセミナーでUnityエンジンはスクリプトが低速で 次世代機で使うのは難しいという評価をしている開発者がいたようです。
まだ発展している段階で 大変バージョンアップの間隔も早いUnityエンジンです。
プラットフォーム自体 パワーがアガるスピードも年々はやまっていますので
現在の処理速度でこのゲームエンジンの評価をしてしまうのは早計だと思います。
他社製品のものに比べて重たいという評ですが 値段的に天と地ほども差がありそうな
高価なエンジンと比べれば多少使い勝手が悪いかも知れませんが この値段でこの性能をたたき出してるのは
むしろ驚愕だと思います。
世界中からの興味をひいているゲームエンジンです。日本にとっても低コストでゲーム開発ができるチャンスだと思いますが、世界中の誰にとってもチャンスなので 現在の研究潜伏期間を経て高いクオリティの作品が
登場するのも時間の問題かと思われます。そうなってしまってからでは日本の開発は更に劣勢に立つことになるわけで、 いまこのエンジンについて使える使えないなどという議論をするのはナンセンスです。
将来登場するさらに高性能のゲームエンジンのための布石としてUnityエンジンに慣れておくのはありだと思います。 そのときになって開発者がゲームエンジンの作法がわからないという状況が訪れはしないかというのが一番の懸念です。
ゲーム業界的にみると国内開発の一番の問題点はプロジェクトの大型化により昔のようにゲームを一人で作成した経験がなく開発全般をコントロールできる開発の人材がいないことがあげられます。海外のように映像系などのモノづくりに特化した教育をうけている開発者がディレクションをしている業界と競争していかなければ勝ち残れないわけで  これからのゲーム開発を考える上でゲーム制作をコントロールできる人材の育成は大変重要なことだと思います。 そういう意味を含めてこのブログではUnityでの開発に関するはなしをしていくつもりなのです。 まあ たいした話もできませんがw


■その他の最適化の関連記事

うにばな 講座みたいなもの番外編(高速化(最適化)について2  自分用のメモ)

うにばな 講座みたいなもの番外編(高速化(最適化)について3 モバイル系

うにばな メモリ使用量の最適化・ヒープメモリ ほか