Unityで恒例のパーティクルテスト

FlashXNASilverlightとかでもやってたようなパーティクルテストをUnityでもやってみた。ゲーム内のオブジェクトをどんくらいのオーダーの数まで扱えるかが知りたい、ってのが主な目的。

結果は、なかなかパフォーマンス的には厳しいかも。Core i7 2.7GHzくらいのマシンなら60フレで850個くらい出せるんだけど、Core 2の1.8GHzだと250個くらい。これノーパソとかだと多分壊滅的だよね、まあGPUにも依存するだろうから一概には言えないけど。

ただまだUnityでの最適化手法が全然分からんので全く最適化してないってのと、Unityには組み込みのパーティクルシステムがあるので、本当のパーティクルはそっちを使えという逃げ道はある。

パーティクルの動作を扱うスクリプトはすごく簡単に書けた。Unityはコルーチンがあるので、yieldを使えばフレームごとに呼び出されるUpdate関数を使わなくてもオブジェクトの動作がかける。これは便利。

import Util;

private var START_SPEED = 3.0;
private var vel:Vector3;

function Start () {
	vel.x = RandZeroCenter(START_SPEED);
	vel.y = (0.3 + Random.value) * START_SPEED;
	vel.z = RandZeroCenter(START_SPEED);
	while (transform.localScale.sqrMagnitude > 0.001) {
		transform.position += vel * Time.deltaTime;
		vel.y -= 5.0 * Time.deltaTime;
		if (transform.position.y < 0) {
			transform.position.y = 0;
			vel.y *= -0.9;
		}
		transform.localScale *= (1 - 1.0 * Time.deltaTime);
		numberOfObjects++;
		yield;
	}
	Destroy(gameObject);
}

ただUnityではFPSは一定でないことを想定して、フレームごとの経過時間を表すTime.deltaTimeを使うのが通常のやり方らしい。これはちょっと面倒。

というわけで、現状Unityで大量のオブジェクトを扱うのは簡単そうではなさげ。ちょっと最適化手法とか、別の逃げ道とかを探してみようかと思う。

(12/23追記) Unity組み込みのパーティクルシステムの方も試してみた。シーンの真ん中にParticleのEmitter、Animator、Renderer付きのGameObject置いただけ。

こっちはパフォーマンス優秀だなあ。Core i7 2.7GHzマシンなら相当数のパーティクル出してもぬるぬる動く。

あとパフォーマンス関係でいろいろ試してみた結果としては、

  • オブジェクトプーリングはあんまりパフォーマンス向上には役に立たなさそう。そもそもUnityには高機能なオブジェクト管理機能があるので、それとは別の管理機能を自前で作るのはあまり筋がよくない
  • Cubeの代わりに50枚くらいの三角形ペラポリゴンのMeshを書いた場合でもパフォーマンスは同じくらい
  • ペラポリゴン1枚にしてもパフォーマンスが劇的に良くなったりはしない
  • レンダリングしないで単にパーティクルのGameObjectを生成、制御するだけなら3.5倍くらいのパーティクルが出せる

なのでUnityでパフォーマンス稼ぐ戦略としては、GameObjectの数は絞ってMeshをレンダリングする回数を減らし、パーティクルは組み込みのものを使う、という感じになりそう。