GPUParticles2D/3D in Godot 4 — Guida completa
1. Introduzione
Godot 4 usa GPUParticles2D e GPUParticles3D come nodi predefiniti per i sistemi di particelle. Vengono eseguiti interamente sulla GPU e per questo sono nettamente più veloci delle controparti CPU quando le particelle sono numerose. Il vecchio ParticlesMaterial di Godot 3 è stato sostituito da ParticleProcessMaterial, che offre maggiore controllo sul comportamento delle particelle.
CPUParticles2D e CPUParticles3D esistono ancora come nodi di fallback per i dispositivi privi di supporto GPU compute o quando devi accedere ai dati delle singole particelle da GDScript. Nella maggior parte dei casi le particelle GPU sono la scelta consigliata.
2. GPUParticles2D vs. CPUParticles2D
| Caratteristica | GPUParticles2D | CPUParticles2D |
|---|---|---|
| Elaborazione | GPU (compute shader) | CPU (thread principale) |
| Particelle max | 100.000+ in modo efficiente | ~1.000-5.000 limite pratico |
| Sub-emitter | Sì | No |
| Trail | Sì | No |
| Accesso per particella | No (solo GPU) | Sì (da GDScript) |
| Modalità compatibilità | Richiede Vulkan/Metal/D3D12 | Funziona ovunque |
| Tipo di materiale | ParticleProcessMaterial | Proprietà integrate (nessun materiale) |
GPUParticles2D come impostazione predefinita. Passa a CPUParticles2D solo se hai bisogno del supporto per il renderer Compatibility, devi leggere le posizioni delle particelle in GDScript o punti a hardware molto datato.
3. Configurazione di base
Per creare un semplice effetto particellare, aggiungi un nodo GPUParticles2D alla scena e assegnagli un ParticleProcessMaterial. Ecco una configurazione minima in 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)
Proprietà chiave sul nodo GPUParticles2D stesso:
amount— Numero di particelle vive in ogni istante (predefinito: 8)lifetime— Durata di vita di ogni particella in secondi (predefinito: 1.0)one_shot— Emette una volta e poi si ferma (predefinito: false)explosiveness— 0.0 = flusso continuo, 1.0 = tutte le particelle in una voltarandomness— Offset casuale sul timing di emissione (0.0-1.0)speed_scale— Moltiplicatore della velocità di simulazioneemitting— Se il sistema sta emettendo in questo momento
4. ParticleProcessMaterial in dettaglio
ParticleProcessMaterial controlla il comportamento delle singole particelle nel corso della loro vita. Tutte le proprietà direzionali usano Vector3, anche per le particelle 2D (la componente Z viene semplicemente ignorata).
Direzione & velocità
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
Velocità angolare
Fa ruotare le particelle durante il movimento. Utile per detriti, coriandoli o foglie.
mat.angular_velocity_min = -180.0 # degrees per second mat.angular_velocity_max = 180.0
Scala nel corso della vita
Usa una CurveTexture per variare la dimensione delle particelle durante la loro vita:
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
Smorzamento & attrattore
Lo smorzamento rallenta le particelle nel tempo, simulando la resistenza dell'aria. Gli attrattori (nodi separati) attirano le particelle verso un punto.
mat.damping_min = 5.0 mat.damping_max = 10.0
5. Gradienti di colore
La proprietà color_ramp del ParticleProcessMaterial accetta una GradientTexture1D per variare in modo fluido il colore delle particelle durante la loro vita. È indispensabile per effetti realistici di fuoco, fumo e magia.
Esempio: gradiente di fuoco
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
Per particelle di colore uniforme, invece di un gradiente puoi anche impostare una proprietà color piatta:
mat.color = Color(0.2, 0.6, 1.0, 0.8) # Semi-transparent blue
6. Forme di emissione
La forma di emissione determina dove nascono le particelle. Si imposta tramite emission_shape sul ParticleProcessMaterial.
Point
Tutte le particelle nascono dall'origine del nodo. È la forma predefinita.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_POINT
Sphere / Sphere Surface
Le particelle nascono casualmente all'interno di una sfera (o solo sulla sua superficie).
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
Le particelle nascono casualmente all'interno di un volume rettangolare.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX mat.emission_box_extents = Vector3(100, 10, 0) # Wide and thin
Ring
Le particelle nascono in una forma ad anello (ciambella), definita da raggio interno/esterno e altezza.
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 con un'ampia estensione X e una Y stretta per creare effetti a livello del suolo, come scie di polvere o particelle dei passi.
7. Ricette pratiche
Fuoco
Gradiente arancione-rosso, velocità verso l'alto, leggera dispersione, scala decrescente nel corso della vita.
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
Fumo
Gradiente grigio, movimento lento verso l'alto, ampia dispersione, alpha basso per un aspetto vaporoso.
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
Pioggia
Strisce bianco-azzurre, forte gravità verso il basso, dispersione stretta, alto numero di particelle.
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
Scintille
Giallo-arancio, esplosione improvvisa, alta velocità iniziale, breve durata di vita.
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
Neve
Particelle bianche, discesa lenta e delicata, ampia dispersione, leggera deriva orizzontale.
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. Particelle 3D (GPUParticles3D)
GPUParticles3D funziona in modo identico a GPUParticles2D, ma opera nello spazio 3D. Viene usato lo stesso ParticleProcessMaterial. Le differenze principali:
- Tutti e 3 gli assi di
Vector3sono attivi (X, Y, Z) - Le forme di emissione funzionano in pieno 3D (le sfere sono vere sfere, le box sono volumi)
- Puoi usare
draw_pass_1con unQuadMesho una mesh personalizzata per particelle billboard - Le particelle mesh possono usare
StandardMaterial3DoORMMaterial3D
# 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 a draw_pass_1 e applicavi un StandardMaterial3D. Ogni particella verrà renderizzata come copia di quella mesh.
9. Sub-emitter
Godot 4 supporta i sub-emitter per effetti particella-su-particella. Un sub-emitter è un altro nodo GPUParticles2D/GPUParticles3D che emette particelle alla posizione di ciascuna particella genitore. È ideale per:
- Scintille che schizzano via dalle particelle di fuoco
- Scie di fumo dietro le esplosioni di fuochi d'artificio
- Gocce di schizzo alla collisione
- Esplosioni secondarie
Come configurare i 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)
Modalità dei sub-emitter:
SUB_EMITTER_CONSTANT— Emette in continuazione da ogni particella genitoreSUB_EMITTER_AT_END— Emette quando la particella genitore muoreSUB_EMITTER_AT_COLLISION— Emette quando la particella genitore collide
GPUParticles, non con CPUParticles. Ogni sub-emitter aumenta il carico della GPU, quindi mantieni basso il numero di particelle dei sub-emitter (4-8 per particella genitore).
10. Consigli sulle prestazioni
-
Compromesso quantità vs. durata di vita:
Particelle visibili totali =
amount. Se aumentilifetime, le particelle si accumulano più a lungo. Riduciamountper compensare, oppure aumentalo per effetti più densi. -
Usa il Visibility Range (3D):
Imposta
visibility_range_endsu GPUParticles3D affinché i sistemi di particelle lontani smettano di essere renderizzati. È un grande vantaggio per i mondi aperti. -
FPS fissi:
Imposta
fixed_fpssul nodo delle particelle (es. 30) per limitare gli aggiornamenti della simulazione. Le particelle continuano a interpolare in modo fluido, ma consumano meno tempo GPU. -
One-shot per le esplosioni:
Per gli effetti di tipo esplosivo usa
one_shot = trueconexplosiveness = 1.0. Il nodo può poi essere liberato al termine della durata di vita. -
Usa il LOD per il 3D:
Combina
visibility_range_begin/endcon più nodi di particelle a diversi livelli di dettaglio per effetti particellari Level of Detail (LOD). -
Evita l'overdraw:
Molte particelle semitrasparenti sovrapposte = fill rate costoso. Riduci
amounte usa invece particelle più grandi con alpha inferiore.
11. Migrazione da Godot 3 a 4
Se stai migrando un progetto da Godot 3 a Godot 4, ecco le modifiche principali per le particelle:
| Godot 3 | Godot 4 | Note |
|---|---|---|
Particles2D |
GPUParticles2D |
Rinominato |
Particles (3D) |
GPUParticles3D |
Rinominato |
ParticlesMaterial |
ParticleProcessMaterial |
Rinominato con nuove funzionalità |
CPUParticles2D |
CPUParticles2D |
Invariato |
CPUParticles |
CPUParticles3D |
Rinominato per chiarezza |
| No sub-emitters | sub_emitter_mode |
Nuovo in Godot 4 |
| No trails | trail_enabled |
Nuovo in Godot 4 |
flag_align_y |
particle_flag_align_y |
Proprietà rinominata |
ParticlesMaterial in GDScript devono essere aggiornati manualmente a ParticleProcessMaterial.
Automatizza gli effetti particellari con MCP Pro
Vuoi che l'IA crei gli effetti particellari al posto tuo? Godot MCP Pro include strumenti dedicati alle particelle con preset per fuoco, fumo, pioggia, neve, scintille e altro ancora. Pieno controllo su materiali, gradienti e forme di emissione da un'unica conversazione.
- create_particles
- set_particle_material
- set_particle_color_gradient
- apply_particle_preset
- get_particle_info