Godot ノードと百万回の更新
Godotエンジン、ノード多いと処理重いはず。でもどれくらい?
やってみたこと
次の8種類のノードをそれぞれ10万個(描画系は1万個)作って、フレームが1周するのに何マイクロ秒かかるか測ってみました。
Node
組み込みクラスです。
Node3D
組み込みクラスです。
Node派生(NoDef)
_processを定義していないNode派生クラスです。
Node派生(pass)
Node派生クラスです。_processを定義してますが、新規作成されたスクリプトと同じで、冒頭でpassするだけで何もしてません。
Node派生(Min)
Node派生クラスです。_processを定義して、メンバ変数をインクリメント(+=1)してます。1行だけの関数。最小の処理という意味でMinです。
Node派生(Itr)
Node派生クラスです。_processを定義して、メンバ変数を100回インクリメント(+=1)してます。for文を使わずに100行使って+1してます。繰り返しのItrです。
Mesh(画面内)
MeshInstance3Dです。meshにsize=0.1のBoxMeshを設定してます。画面には米粒くらいの大きさで描かれます。MeshInstance3Dは10万個作ると、Godotが応答しなくなったので、これは1万個だけ作ってます。
Mesh(画面外)
MeshInstance3Dです。meshにsize=0.1のBoxMeshを設定してます。カメラの後ろに配置してます。こうすることで、カリングされて描画発行されない、もしくは頂点シェーダーだけが走ってピクセルシェーダーに至らない、という狙いです。これも10万個ではなく、1万個だけ作ってます。
# 1回だけの処理 -------------
# 通常のノード作成の場合
for i in range(0, GDSpeedNode.NODE_COUNT):
add_child(NodeProcPass.new())
# 描画系ノードの作成の場合
for i in range(0, GDSpeedNode.NODE_COUNT / 10):
var mesh_inst: MeshInstance3D = MeshInstance3D.new()
mesh_inst.mesh = mesh
mesh_inst.position = Vector3(0.0, 0.0, 8.0) # 画面外
add_child(mesh_inst)
# 毎フレームの処理 --------------
# プロジェクト設定の「垂直同期モード」をDisableにしてます。
var time: int = Time.get_ticks_usec()
_time_sum += (time - _last_time)
_last_time = time
_time_count += 1
if _time_count > 100 or _time_sum > 1_000_000:
var time_ave: int = int(float(_time_sum) / float(_time_count))
print("time[us] %d" % time_ave)
_time_sum = 0
_time_count = 0
結果
2台のパソコンで実行してみました。ビルドとかしてなくて、エディタ上での実行です。エディタ上で「遊べる」重さで動くことは、制作初期段階でも重要だと思うので。
パソコンA: Ryzen 5 7520U 2.8GHz
パソコンB: Ryzen 3 2200G 3.5GHz
わかったこと
単なるNodeやNode3Dを作ってツリーに加えただけでは、速度に影響しないようです。
組み込みのNodeと、自作の派生クラスでは、_processを定義しない限り、差は見られませんでした。
_processを定義していると、たとえpassするだけの関数であっても、顕著に影響が出ます。10万(100k)個あると、_processの呼び出しに90msかかってしまうので、10f/sくらいまで落ち込む見込みです。
MeshInstance3Dは、たとえ画面に映っていたとしても、自作の_processほどは時間は取らないようです。とはいえ、1万個で数msかかってるので、100 x 100や20 x 20 x 20みたいに、何かをずらーっと並べようとすると、それなりに負荷がかかると思ってよさそうです。
大量に出現するノードは、_process無いほうが良さそうです。
↓ 要らないなら消そう~!
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
以上です~~
この記事が気に入ったらサポートをしてみませんか?