Godot 4のGPUParticles2D/3D 完全ガイド
1. はじめに
Godot 4ではGPUParticles2DとGPUParticles3Dがデフォルトのパーティクルシステムノードです。GPU上で完全に実行されるため、大量のパーティクルでもCPU版より大幅に高速です。Godot 3のParticlesMaterialはParticleProcessMaterialに置き換えられ、パーティクルの動作をより細かく制御できるようになりました。
CPUParticles2DとCPUParticles3Dは、GPUコンピュートをサポートしないデバイス向け、またはGDScriptから個々のパーティクルデータにアクセスする必要がある場合のフォールバックとして引き続き利用可能です。ほとんどのケースではGPUパーティクルが推奨されます。
2. GPUParticles2D vs CPUParticles2D
| 特徴 | GPUParticles2D | CPUParticles2D |
|---|---|---|
| 処理 | GPU(コンピュートシェーダー) | CPU(メインスレッド) |
| 最大パーティクル数 | 100,000+でも高速 | 実用的には1,000-5,000が限界 |
| サブエミッター | 対応 | 非対応 |
| トレイル | 対応 | 非対応 |
| 個別パーティクルアクセス | 不可(GPU専用) | 可能(GDScriptから) |
| 互換モード | Vulkan/Metal/D3D12が必要 | どこでも動作 |
| マテリアル型 | ParticleProcessMaterial | 組み込みプロパティ(マテリアル不要) |
GPUParticles2Dを使いましょう。Compatibilityレンダラー対応、GDScriptでのパーティクル位置読み取り、または非常に古いハードウェアをターゲットにする場合のみCPUParticles2Dに切り替えてください。
3. 基本セットアップ
基本的なパーティクルエフェクトを作成するには、シーンにGPUParticles2Dノードを追加し、ParticleProcessMaterialを割り当てます。GDScriptでの最小構成は以下の通りです:
# Create a GPUParticles2D node via code var particles = GPUParticles2D.new() particles.amount = 50 particles.lifetime = 2.0 particles.explosiveness = 0.0 # 0 = continuous, 1 = all at once particles.randomness = 0.5 # Create and assign the material var mat = ParticleProcessMaterial.new() mat.direction = Vector3(0, -1, 0) # Note: uses Vector3 even in 2D mat.initial_velocity_min = 50.0 mat.initial_velocity_max = 100.0 mat.gravity = Vector3(0, 98, 0) particles.process_material = mat add_child(particles)
GPUParticles2Dノードの主要プロパティ:
amount— 同時に存在するパーティクル数(デフォルト: 8)lifetime— 各パーティクルの生存時間(秒)(デフォルト: 1.0)one_shot— 一度だけ放出して停止(デフォルト: false)explosiveness— 0.0 = 連続放出、1.0 = 全パーティクルを一度に放出randomness— 放出タイミングのランダムオフセット(0.0-1.0)speed_scale— シミュレーション速度の倍率emitting— 現在放出中かどうか
4. ParticleProcessMaterial 詳解
ParticleProcessMaterialは個々のパーティクルのライフタイム中の動作を制御します。2Dパーティクルでも方向プロパティはすべてVector3を使用します(Z成分は単に無視されます)。
方向と速度
var mat = ParticleProcessMaterial.new() # Direction: normalized vector for initial particle heading mat.direction = Vector3(0, -1, 0) # Upward in 2D (Y is flipped) # Spread: cone angle in degrees (0 = straight line, 180 = hemisphere) mat.spread = 45.0 # Initial velocity: particles spawn with speed in this range mat.initial_velocity_min = 100.0 mat.initial_velocity_max = 200.0 # Gravity: constant acceleration applied every frame mat.gravity = Vector3(0, 98, 0) # Pulls downward in 2D
角速度
パーティクルを移動中に回転させます。破片、紙吹雪、落ち葉などに便利です。
mat.angular_velocity_min = -180.0 # degrees per second mat.angular_velocity_max = 180.0
ライフタイム中のスケール変化
CurveTextureを使ってパーティクルサイズをライフタイム中に変化させます:
var curve = Curve.new() curve.add_point(Vector2(0.0, 1.0)) # Full size at birth curve.add_point(Vector2(0.5, 1.2)) # Slightly larger at midlife curve.add_point(Vector2(1.0, 0.0)) # Shrink to nothing at death var curve_tex = CurveTexture.new() curve_tex.curve = curve mat.scale_curve = curve_tex
減衰とアトラクター
ダンピングはパーティクルを時間とともに減速させ、空気抵抗をシミュレートします。アトラクター(別ノード)はパーティクルをポイントに引き寄せます。
mat.damping_min = 5.0 mat.damping_max = 10.0
5. カラーグラデーション
ParticleProcessMaterialのcolor_rampプロパティはGradientTexture1Dを受け取り、パーティクルの色をライフタイム中に滑らかに変化させます。リアルな炎、煙、魔法エフェクトに不可欠です。
炎のグラデーション例
var gradient = Gradient.new()
gradient.colors = PackedColorArray([
Color(1.0, 1.0, 1.0, 1.0), # White (hot core)
Color(1.0, 1.0, 0.2, 1.0), # Yellow
Color(1.0, 0.5, 0.0, 1.0), # Orange
Color(0.8, 0.1, 0.0, 0.8), # Red
Color(0.2, 0.0, 0.0, 0.0), # Dark red, transparent (fade out)
])
gradient.offsets = PackedFloat32Array([0.0, 0.15, 0.4, 0.7, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = gradient
mat.color_ramp = grad_tex
均一な色のパーティクルにはグラデーションの代わりにフラットなcolorプロパティも設定できます:
mat.color = Color(0.2, 0.6, 1.0, 0.8) # Semi-transparent blue
6. エミッション形状
エミッション形状はパーティクルの出現位置を決定します。ParticleProcessMaterialのemission_shapeで設定します。
Point
全パーティクルがノードの原点から出現します。デフォルトの形状です。
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_POINT
Sphere / Sphere Surface
パーティクルが球体内(またはその表面上のみ)にランダムに出現します。
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE mat.emission_sphere_radius = 50.0 # Surface only: mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE_SURFACE mat.emission_sphere_radius = 50.0
Box
パーティクルが矩形ボリューム内にランダムに出現します。
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX mat.emission_box_extents = Vector3(100, 10, 0) # Wide and thin
Ring
パーティクルがリング(ドーナツ)形状に出現します。内径/外径/高さで定義されます。
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_RING mat.emission_ring_radius = 80.0 # Outer radius mat.emission_ring_inner_radius = 60.0 # Inner radius (hole) mat.emission_ring_height = 0.0 # Flat ring mat.emission_ring_axis = Vector3(0, 0, 1) # Ring normal
EMISSION_SHAPE_BOXでXを広く、Yを狭くすると、砂ぼこりや足跡パーティクルのような地面レベルのエフェクトを作成できます。
7. 実践レシピ
炎
オレンジ~赤のグラデーション、上方向の速度、わずかな広がり、ライフタイム中にスケール縮小。
func create_fire() -> GPUParticles2D:
var p = GPUParticles2D.new()
p.amount = 40
p.lifetime = 0.8
p.randomness = 0.3
var mat = ParticleProcessMaterial.new()
mat.direction = Vector3(0, -1, 0)
mat.spread = 15.0
mat.initial_velocity_min = 40.0
mat.initial_velocity_max = 80.0
mat.gravity = Vector3(0, -20, 0) # Slight upward pull
mat.damping_min = 5.0
mat.damping_max = 10.0
# Color ramp: white -> yellow -> orange -> red -> transparent
var grad = Gradient.new()
grad.colors = PackedColorArray([
Color(1, 1, 1, 1), Color(1, 1, 0.2, 1),
Color(1, 0.4, 0, 0.9), Color(0.6, 0.1, 0, 0.4),
Color(0.2, 0, 0, 0)
])
grad.offsets = PackedFloat32Array([0.0, 0.1, 0.35, 0.7, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = grad
mat.color_ramp = grad_tex
# Scale: shrink over time
var curve = Curve.new()
curve.add_point(Vector2(0, 0.8))
curve.add_point(Vector2(0.3, 1.0))
curve.add_point(Vector2(1, 0.0))
var curve_tex = CurveTexture.new()
curve_tex.curve = curve
mat.scale_curve = curve_tex
p.process_material = mat
return p
煙
灰色のグラデーション、ゆっくりとした上昇、大きな広がり、低アルファで薄い見た目。
func create_smoke() -> GPUParticles2D:
var p = GPUParticles2D.new()
p.amount = 25
p.lifetime = 3.0
p.randomness = 0.5
var mat = ParticleProcessMaterial.new()
mat.direction = Vector3(0, -1, 0)
mat.spread = 35.0
mat.initial_velocity_min = 10.0
mat.initial_velocity_max = 30.0
mat.gravity = Vector3(0, -5, 0)
mat.damping_min = 2.0
mat.damping_max = 5.0
mat.angular_velocity_min = -30.0
mat.angular_velocity_max = 30.0
var grad = Gradient.new()
grad.colors = PackedColorArray([
Color(0.6, 0.6, 0.6, 0.0), Color(0.5, 0.5, 0.5, 0.3),
Color(0.4, 0.4, 0.4, 0.2), Color(0.3, 0.3, 0.3, 0.0)
])
grad.offsets = PackedFloat32Array([0.0, 0.15, 0.6, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = grad
mat.color_ramp = grad_tex
# Scale: grow over time (smoke expands)
var curve = Curve.new()
curve.add_point(Vector2(0, 0.3))
curve.add_point(Vector2(0.5, 1.0))
curve.add_point(Vector2(1, 1.5))
var curve_tex = CurveTexture.new()
curve_tex.curve = curve
mat.scale_curve = curve_tex
p.process_material = mat
return p
雨
青白い線、強い下向きの重力、狭い広がり、大量のパーティクル。
func create_rain() -> GPUParticles2D:
var p = GPUParticles2D.new()
p.amount = 200
p.lifetime = 1.0
# Use a box emission to cover the screen width
var mat = ParticleProcessMaterial.new()
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
mat.emission_box_extents = Vector3(600, 0, 0)
mat.direction = Vector3(0.05, 1, 0) # Slightly angled
mat.spread = 3.0
mat.initial_velocity_min = 400.0
mat.initial_velocity_max = 500.0
mat.gravity = Vector3(0, 200, 0)
var grad = Gradient.new()
grad.colors = PackedColorArray([
Color(0.7, 0.8, 1.0, 0.6), Color(0.7, 0.85, 1.0, 0.4),
Color(0.7, 0.85, 1.0, 0.0)
])
grad.offsets = PackedFloat32Array([0.0, 0.8, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = grad
mat.color_ramp = grad_tex
# Stretch particles to look like streaks
mat.scale_min = 0.5
mat.scale_max = 0.5
p.process_material = mat
return p
火花
黄色~オレンジ、爆発的な放出、高い初速度、短いライフタイム。
func create_sparks() -> GPUParticles2D:
var p = GPUParticles2D.new()
p.amount = 30
p.lifetime = 0.5
p.one_shot = true
p.explosiveness = 1.0 # All at once
var mat = ParticleProcessMaterial.new()
mat.direction = Vector3(0, -1, 0)
mat.spread = 180.0 # Full sphere
mat.initial_velocity_min = 150.0
mat.initial_velocity_max = 300.0
mat.gravity = Vector3(0, 200, 0) # Fall quickly
mat.damping_min = 10.0
mat.damping_max = 20.0
var grad = Gradient.new()
grad.colors = PackedColorArray([
Color(1, 1, 0.8, 1), Color(1, 0.7, 0.1, 1),
Color(1, 0.3, 0, 0.5), Color(0.5, 0.1, 0, 0)
])
grad.offsets = PackedFloat32Array([0.0, 0.2, 0.6, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = grad
mat.color_ramp = grad_tex
# Scale: start small, stay small
mat.scale_min = 0.3
mat.scale_max = 0.6
p.process_material = mat
return p
雪
白いパーティクル、ゆっくりとした穏やかな降下、広い範囲、わずかな水平方向のドリフト。
func create_snow() -> GPUParticles2D:
var p = GPUParticles2D.new()
p.amount = 100
p.lifetime = 5.0
p.randomness = 0.8
var mat = ParticleProcessMaterial.new()
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
mat.emission_box_extents = Vector3(500, 0, 0)
mat.direction = Vector3(0.1, 1, 0)
mat.spread = 10.0
mat.initial_velocity_min = 20.0
mat.initial_velocity_max = 40.0
mat.gravity = Vector3(0, 10, 0)
mat.damping_min = 1.0
mat.damping_max = 3.0
mat.angular_velocity_min = -45.0
mat.angular_velocity_max = 45.0
var grad = Gradient.new()
grad.colors = PackedColorArray([
Color(1, 1, 1, 0), Color(1, 1, 1, 0.8),
Color(1, 1, 1, 0.7), Color(1, 1, 1, 0)
])
grad.offsets = PackedFloat32Array([0.0, 0.05, 0.8, 1.0])
var grad_tex = GradientTexture1D.new()
grad_tex.gradient = grad
mat.color_ramp = grad_tex
mat.scale_min = 0.3
mat.scale_max = 0.8
p.process_material = mat
return p
8. 3Dパーティクル (GPUParticles3D)
GPUParticles3DはGPUParticles2Dと同じ仕組みですが、3D空間で動作します。同じParticleProcessMaterialを使用します。主な違い:
Vector3の3軸すべてが有効(X, Y, Z)- エミッション形状が完全な3Dで動作(球は本物の球体、ボックスはボリューム)
draw_pass_1にQuadMeshやカスタムメッシュを使ってビルボードパーティクルを作成可能- メッシュパーティクルには
StandardMaterial3DやORMMaterial3Dを使用可能
# 3D fire torch example var particles_3d = GPUParticles3D.new() particles_3d.amount = 60 particles_3d.lifetime = 1.0 var mat = ParticleProcessMaterial.new() mat.direction = Vector3(0, 1, 0) # Upward in 3D mat.spread = 20.0 mat.initial_velocity_min = 1.0 mat.initial_velocity_max = 2.0 mat.gravity = Vector3(0, -0.5, 0) # Slight counter-gravity # Emission from a small sphere mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE mat.emission_sphere_radius = 0.2 particles_3d.process_material = mat # Use a QuadMesh as the particle shape var quad = QuadMesh.new() quad.size = Vector2(0.3, 0.3) particles_3d.draw_pass_1 = quad # Billboard mode: particles always face the camera mat.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED add_child(particles_3d)
.tresメッシュをdraw_pass_1に割り当て、StandardMaterial3Dを適用します。各パーティクルがそのメッシュのコピーとしてレンダリングされます。
9. サブエミッター
Godot 4はパーティクルからパーティクルを生成するサブエミッターに対応しています。サブエミッターは、親パーティクルの位置で新たなパーティクルを放出する別のGPUParticles2D/GPUParticles3Dノードです。以下に最適です:
- 炎パーティクルから飛び散る火花
- 花火の爆発後の煙の軌跡
- 衝突時の飛沫
- 二次爆発
サブエミッターのセットアップ方法:
# 1. Create the sub-emitter node (must be a sibling or child) var sub_sparks = GPUParticles2D.new() sub_sparks.amount = 4 sub_sparks.lifetime = 0.3 sub_sparks.explosiveness = 1.0 sub_sparks.emitting = false # Controlled by parent var sub_mat = ParticleProcessMaterial.new() sub_mat.direction = Vector3(0, -1, 0) sub_mat.spread = 180.0 sub_mat.initial_velocity_min = 50.0 sub_mat.initial_velocity_max = 100.0 sub_sparks.process_material = sub_mat add_child(sub_sparks) # 2. Reference it from the parent material var parent_mat: ParticleProcessMaterial = fire_particles.process_material parent_mat.sub_emitter_mode = ParticleProcessMaterial.SUB_EMITTER_AT_END # Also: SUB_EMITTER_AT_COLLISION, SUB_EMITTER_CONSTANT # 3. Set the sub_emitter property on the parent node fire_particles.sub_emitter = fire_particles.get_path_to(sub_sparks)
サブエミッターモード:
SUB_EMITTER_CONSTANT— 各親パーティクルから連続的に放出SUB_EMITTER_AT_END— 親パーティクルが消滅する時に放出SUB_EMITTER_AT_COLLISION— 親パーティクルが衝突した時に放出
GPUParticlesでのみ動作し、CPUParticlesでは使用できません。サブエミッターごとにGPU負荷が増えるため、サブエミッターのパーティクル数は少なく保ちましょう(親パーティクルあたり4-8個)。
10. パフォーマンスのコツ
-
数量 vs ライフタイムのトレードオフ:
同時表示パーティクル数 =
amount。lifetimeを増やすとパーティクルが長く残ります。補正のためamountを減らすか、より密度の高いエフェクトにするため増やしてください。 -
Visibility Range(3D)を使う:
GPUParticles3Dに
visibility_range_endを設定すると、遠くのパーティクルシステムがレンダリングされなくなります。オープンワールドでは大きな効果があります。 -
固定FPS:
パーティクルノードに
fixed_fpsを設定(例: 30)するとシミュレーション更新が制限されます。パーティクルは滑らかに補間されますがGPU使用量は減ります。 -
バースト用のOne-shot:
爆発エフェクトには
one_shot = trueとexplosiveness = 1.0を使用します。ライフタイム終了後にノードを解放できます。 -
3DでのLOD活用:
visibility_range_begin/endを複数の異なる詳細レベルのパーティクルノードと組み合わせて、LOD(Level of Detail)パーティクルエフェクトを実現できます。 -
オーバードローを避ける:
半透明パーティクルが大量に重なる = フィルレートのコスト増大。
amountを減らし、低アルファの大きなパーティクルを使いましょう。
11. Godot 3から4への移行
Godot 3からGodot 4にプロジェクトを移行する場合、パーティクルの主な変更点は以下の通りです:
| Godot 3 | Godot 4 | 備考 |
|---|---|---|
Particles2D |
GPUParticles2D |
名称変更 |
Particles (3D) |
GPUParticles3D |
名称変更 |
ParticlesMaterial |
ParticleProcessMaterial |
新機能を含む名称変更 |
CPUParticles2D |
CPUParticles2D |
変更なし |
CPUParticles |
CPUParticles3D |
明確化のため名称変更 |
| No sub-emitters | sub_emitter_mode |
Godot 4で新規追加 |
| No trails | trail_enabled |
Godot 4で新規追加 |
flag_align_y |
particle_flag_align_y |
プロパティ名変更 |
ParticlesMaterial参照は手動でParticleProcessMaterialに更新する必要があります。
MCP Proでパーティクルエフェクトを自動化
AIにパーティクルエフェクトを作成させたいですか?Godot MCP Proには、炎、煙、雨、雪、火花などのプリセット付き専用パーティクルツールが含まれています。マテリアル、グラデーション、エミッション形状を会話一つで完全制御。
- create_particles
- set_particle_material
- set_particle_color_gradient
- apply_particle_preset
- get_particle_info