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 的實用上限 |
| Sub-Emitter | 支援 | 不支援 |
| 拖尾 (Trails) | 支援 | 不支援 |
| 逐粒子存取 | 不支援(僅 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 控制個別粒子在其生命週期中的行為。所有方向屬性都使用 Vector3,即使是 2D 粒子也一樣(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
煙霧
灰色漸層、緩慢的上升運動、大範圍擴散,以及低 Alpha 值以呈現輕飄的外觀。
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或自訂網格使用,來製作看板 (Billboard) 粒子 - 網格粒子可以使用
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. Sub-Emitter
Godot 4 支援 Sub-Emitter,用於粒子產生粒子的效果。Sub-Emitter 是另一個 GPUParticles2D/GPUParticles3D 節點,會在每個父粒子的位置發射粒子。它非常適合用於:
- 從火焰粒子飛散出的火花
- 煙火爆炸後方的煙霧尾跡
- 碰撞時的飛濺水滴
- 二次爆炸
以下是設定 Sub-Emitter 的方式:
# 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 模式:
SUB_EMITTER_CONSTANT— 從每個父粒子連續發射SUB_EMITTER_AT_END— 當父粒子消亡時發射SUB_EMITTER_AT_COLLISION— 當父粒子碰撞時發射
GPUParticles 搭配運作,無法用於 CPUParticles。每個 Sub-Emitter 都會增加 GPU 負載,因此請將 Sub-Emitter 的粒子數保持在較低水準(每個父粒子 4-8 個)。
10. 效能技巧
-
數量與生命週期的取捨:
總可見粒子數 =
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) 粒子效果。 -
避免過度繪製 (Overdraw):
大量彼此重疊的半透明粒子 = 昂貴的填充率。請減少
amount,改用較大且 Alpha 值較低的粒子。
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