ゾンビとUnity

ゾンビネタとUnityでのゲーム制作について綴るブログです。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Unity ゲーム製作 9 キューブ2万5千個を高速に作ることはできるのか?

前回の記事
Unity ゲーム製作 8 ボクセルテレインのプロトタイプ
http://bosukete666.blog.fc2.com/blog-entry-263.html

GameObject の Cube を使い、2万5千個のキューブからなるボクセルテレインを作ったのですが、作り終わるまでに数十秒かかってしまいました。
プロトタイプとは言え、さすがに遅すぎるだろう…ということで、もう少し速く作る方法はないのか?を調べます。

キューブは、ゲーム実行時に GameObject.CreatePrimitive() を使って作成。
もし、このメソッドが重いのなら、他の方法でキューブを作る必要があります。
他に思いつくのは Instantiate() か、自分でメッシュを作るかですが、後者は断固として拒否します。
なので、CreatePrimitive() と Instantiate() の処理スピードを比較してみます。

もし、Instantiate() の方が遅いという結果になった場合、打つ手なし。どうしようもありません。


速度比較に使ったスクリプト
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour {

public GameObject original;

void Start () {
int trying = 10000;
float start = Time.realtimeSinceStartup;
// this.CreatePrimitiveTest(trying);
// this.InstantiateTest(trying);

float elapsed = Time.realtimeSinceStartup - start;
Debug.Log("elapsed time : " + (float)(elapsed * 1000) + "ms");
}

void CreatePrimitiveTest(int repeat) {
for (int i = 0; i < repeat; i++) {
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
}

void InstantiateTest(int repeat) {
for (int i = 0; i < repeat; i++) {
UnityEngine.Object.Instantiate(this.original, Vector3.zero, Quaternion.identity);
}
}
}

CreatePrimitive() の処理スピードを計測したいときは、this.CreatePrimitiveTest(trying); のコメントアウトを外し(行頭の//を削除する)、Instantiate() なら this.InstantiateTest(trying); のコメントアウトを外して計測。
original には、あらかじめ作っておいたキューブを設定しておきます。

私の環境では、CreatePrimitive() を1万回実行した場合にかかる時間は、291~296ミリセカンドくらい。
Inistantiate() では 1800~2200ミリセカンドくらいでした。

これにタグを設定したり、位置を設定したり、スケールを設定したり、マテリアルを設定したりという処理が追加されて、試行回数も1万回から2万5千回に増えて更に遅くなるわけですが、それでどれくらいの差がつくのかを試してみました。

結果

CreatePrimitive() の方が圧倒的に速い。


詰んだ…。

4b2c9857.jpg


でも、それだとひとつの疑問が浮かびます。

CreatePrimitive() を使っていたのに、何であんなに遅くなったのか?

余計なことをしなければ、2万5千個のキューブで地形を作るのに2秒もかからないはず。
それが数十秒かかるということは、キューブを作るのとは別の場所で、バカみたいに時間を食っていたということ。

犯人は誰だ!



フハハハハ!Instantiate() が遅いだと?
オマエは騙されている!


ひとつ面白い現象に遭遇したので、書き残しておきます。
なんでこんな事が起きるのが、原因が分かりません。

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour {

public GameObject original;
public Material material;

void Start () {
int trying = 25000;
float start = Time.realtimeSinceStartup;
// this.CreatePrimitiveTest(trying);
// this.InstantiateTest(trying);

float elapsed = Time.realtimeSinceStartup - start;
Debug.Log("elapsed time : " + elapsed + "sec.");
}

void CreatePrimitiveTest(int repeat) {
GameObject g;
for (int i = 0; i < repeat; i++) {
g = GameObject.CreatePrimitive(PrimitiveType.Cube);
// g.transform.parent = this.transform;
g.name = "test-" + i;
g.tag = "Test";
g.transform.position = new Vector3(i, 0, 0);
g.transform.localScale = new Vector3(1, 0.5f, 1);
g.GetComponent<MeshRenderer>().material = this.material;
}
}

void InstantiateTest(int repeat) {
GameObject g;
for (int i = 0; i < repeat; i++) {
g = (GameObject)UnityEngine.Object.Instantiate(this.original, new Vector3(i, 0, 0), Quaternion.identity);
// g.transform.parent = this.transform;
g.name = "test-" + i;
g.transform.localScale = new Vector3(1, 0.5f, 1);
g.GetComponent<MeshRenderer>().material = this.material;
}
}
}

最初のスクリプトに名前、タグ、位置、スケール、マテリアルを設定する処理を追加しただけです。
同じように、CreatePrimitive() の速度を計りたいときは、this.CreatePrimitiveTest(trying); のコメントアウトだけ外し、Instantiate() のときは this.InstantiateTest(trying); のコメントアウトだけ外します。
original には、tag に Test を設定したキューブを設定しておきます(Testタグは自分で作る)。
material には、適当に作ったマテリアルを設定しておきます(Assets→Create→MaterialしただけのものでOK)。

このスクリプトで速度比較をすると、やっぱり CreatePrimitive() の方が速いという結果が得られます(私の環境では)。
ところがもうひとつ、transform.parent を設定している箇所(赤字の部分)があり、コメントアウトしてるので処理はされません。
このコメントアウトを外すと、面白い現象が起こります。

私の環境では、InstantiateTest(25000) の処理スピードは14~19秒くらいでしたが、transform.parent の行を有効にすると、1秒未満で処理が終わりました。
普通は、なんらかの処理を追加したら、その分、遅くなるはずです。
最大で18秒も速くなる理由がさっぱり分かりません。

CreatePrimitiveTest(25000) の方は順当に遅くなります。
transform.parent がない場合は0.9秒くらいですが、ある場合は1.1秒くらいです。
こちらは「まあ、そんなもんだろう」と、予想通りの結果となるので分かります。

ということは

何回も Instantiate() する場合は親を設定すると爆速化する?
 
キューブの個数を3万、4万と増やしても、やっぱり親を設定した Instantiate() の方が若干速い。
思わぬ発見にめぐり合えたのは嬉しいのですが、速くなった原因が分からないので、この結果を信用して処理を作っても大丈夫なのか不安です。

いや、どっちがいいのか判断できないなら、CreatePrimitive() を使うか、Instantiate() を使うか、選べるようにすれば良いんだ!
 
スポンサーサイト

- 0 Comments

Add your comment

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。