GPUParticles2D/3D en Godot 4 — Guía completa
1. Introducción
Godot 4 usa GPUParticles2D y GPUParticles3D como nodos de sistema de partículas predeterminados. Se ejecutan por completo en la GPU, lo que los hace considerablemente más rápidos que sus equivalentes en CPU cuando hay grandes cantidades de partículas. El antiguo ParticlesMaterial de Godot 3 ha sido reemplazado por ParticleProcessMaterial, que ofrece más control sobre el comportamiento de las partículas.
CPUParticles2D y CPUParticles3D siguen existiendo como nodos de reserva para dispositivos que carecen de soporte de cómputo en GPU o cuando necesitas acceder a los datos de partículas individuales desde GDScript. Para la mayoría de los casos de uso, las partículas de GPU son la opción recomendada.
2. GPUParticles2D vs CPUParticles2D
| Característica | GPUParticles2D | CPUParticles2D |
|---|---|---|
| Procesamiento | GPU (compute shader) | CPU (hilo principal) |
| Máximo de partículas | 100.000+ de forma eficiente | Límite práctico de ~1.000-5.000 |
| Sub-emisores | Sí | No |
| Estelas (trails) | Sí | No |
| Acceso por partícula | No (solo GPU) | Sí (desde GDScript) |
| Modo de compatibilidad | Requiere Vulkan/Metal/D3D12 | Funciona en todas partes |
| Tipo de material | ParticleProcessMaterial | Propiedades integradas (sin material) |
GPUParticles2D por defecto. Cambia a CPUParticles2D solo si necesitas soporte del renderizador Compatibility, necesitas leer las posiciones de las partículas en GDScript o apuntas a hardware muy antiguo.
3. Configuración básica
Para crear un efecto de partículas básico, añade un nodo GPUParticles2D a tu escena y asígnale un ParticleProcessMaterial. Aquí tienes una configuración mínima en 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)
Propiedades clave del propio nodo GPUParticles2D:
amount— Número de partículas vivas en cualquier momento (predeterminado: 8)lifetime— Cuánto vive cada partícula en segundos (predeterminado: 1.0)one_shot— Emitir una vez y detenerse (predeterminado: false)explosiveness— 0.0 = flujo continuo, 1.0 = todas las partículas a la vezrandomness— Desplazamiento aleatorio del tiempo de emisión (0.0-1.0)speed_scale— Multiplicador de la velocidad de simulaciónemitting— Si el sistema está emitiendo actualmente
4. ParticleProcessMaterial en profundidad
ParticleProcessMaterial controla cómo se comportan las partículas individuales a lo largo de su vida. Todas las propiedades direccionales usan Vector3, incluso para partículas 2D (el componente Z simplemente se ignora).
Dirección y velocidad
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
Velocidad angular
Hace girar las partículas mientras se mueven. Útil para escombros, confeti u hojas.
mat.angular_velocity_min = -180.0 # degrees per second mat.angular_velocity_max = 180.0
Escala a lo largo de la vida
Usa una CurveTexture para cambiar el tamaño de la partícula a lo largo de su vida:
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
Amortiguación y atractor
La amortiguación ralentiza las partículas con el tiempo, simulando la resistencia del aire. Los atractores (nodos independientes) atraen las partículas hacia un punto.
mat.damping_min = 5.0 mat.damping_max = 10.0
5. Gradientes de color
La propiedad color_ramp de ParticleProcessMaterial acepta una GradientTexture1D para cambiar suavemente el color de la partícula a lo largo de su vida. Esto es esencial para efectos realistas de fuego, humo y magia.
Ejemplo de gradiente de fuego
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
También puedes establecer una propiedad color plana en lugar de un gradiente para partículas de color uniforme:
mat.color = Color(0.2, 0.6, 1.0, 0.8) # Semi-transparent blue
6. Formas de emisión
La forma de emisión determina dónde aparecen las partículas. Se establece mediante emission_shape en ParticleProcessMaterial.
Point
Todas las partículas aparecen en el origen del nodo. Forma predeterminada.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_POINT
Sphere / Sphere Surface
Las partículas aparecen aleatoriamente dentro de una esfera (o solo en su 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
Las partículas aparecen aleatoriamente dentro de un volumen rectangular.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX mat.emission_box_extents = Vector3(100, 10, 0) # Wide and thin
Ring
Las partículas aparecen en una forma de anillo (dónut), definida por el radio interior/exterior y la altura.
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 una extensión X amplia y una Y estrecha para crear efectos a nivel del suelo, como estelas de polvo o partículas de pisadas.
7. Recetas prácticas
Fuego
Gradiente naranja-rojo, velocidad hacia arriba, ligera dispersión, escala decreciente a lo largo de la vida.
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
Humo
Gradiente gris, movimiento lento hacia arriba, gran dispersión, alpha bajo para un aspecto tenue.
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
Lluvia
Trazos azul-blanco, gravedad fuerte hacia abajo, dispersión estrecha, alto número de partículas.
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
Chispas
Amarillo-naranja, ráfaga explosiva, alta velocidad inicial, vida corta.
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
Nieve
Partículas blancas, descenso lento y suave, amplia dispersión, ligera deriva horizontal.
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. Partículas 3D (GPUParticles3D)
GPUParticles3D funciona de forma idéntica a GPUParticles2D, pero opera en el espacio 3D. Se usa el mismo ParticleProcessMaterial. Diferencias clave:
- Los 3 ejes de
Vector3están activos (X, Y, Z) - Las formas de emisión funcionan en 3D completo (las esferas son esferas reales, las cajas son volúmenes)
- Puedes usar
draw_pass_1con unQuadMesho una malla personalizada para partículas billboard - Las partículas de malla pueden usar
StandardMaterial3DuORMMaterial3D
# 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 personalizada a draw_pass_1 y aplícale un StandardMaterial3D. Cada partícula se renderizará como una copia de esa malla.
9. Sub-emisores
Godot 4 admite sub-emisores para efectos de partícula sobre partícula. Un sub-emisor es otro nodo GPUParticles2D/GPUParticles3D que emite partículas en la posición de cada partícula padre. Es ideal para:
- Chispas que saltan de las partículas de fuego
- Estelas de humo tras las explosiones de fuegos artificiales
- Gotas de salpicadura al colisionar
- Explosiones secundarias
Para configurar los sub-emisores:
# 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)
Modos de sub-emisor:
SUB_EMITTER_CONSTANT— Emite continuamente desde cada partícula padreSUB_EMITTER_AT_END— Emite cuando la partícula padre muereSUB_EMITTER_AT_COLLISION— Emite cuando la partícula padre colisiona
GPUParticles, no con CPUParticles. Cada sub-emisor añade carga a la GPU, así que mantén bajo el número de partículas de los sub-emisores (4-8 por partícula padre).
10. Consejos de rendimiento
-
Compromiso entre cantidad y vida:
El total de partículas visibles =
amount. Si aumentaslifetime, las partículas se acumulan durante más tiempo. Reduceamountpara compensar, o auméntalo para efectos más densos. -
Usa Visibility Range (3D):
Establece
visibility_range_enden GPUParticles3D para que los sistemas de partículas lejanos dejen de renderizarse. Es una gran ventaja para los mundos abiertos. -
FPS fijos:
Establece
fixed_fpsen el nodo de partículas (p. ej., 30) para limitar las actualizaciones de simulación. Las partículas seguirán interpolándose con suavidad, pero usarán menos tiempo de GPU. -
One-shot para ráfagas:
Para efectos tipo explosión, usa
one_shot = trueconexplosiveness = 1.0. Luego puedes liberar el nodo una vez que termina la vida. -
Usa LOD para 3D:
Combina
visibility_range_begin/endcon varios nodos de partículas en distintos niveles de detalle para efectos de partículas con Nivel de Detalle (LOD). -
Evita el overdraw:
Muchas partículas semitransparentes superpuestas = una fill rate costosa. Reduce
amounty usa en su lugar partículas más grandes con menor alpha.
11. Migración de Godot 3 a 4
Si estás migrando un proyecto de Godot 3 a Godot 4, estos son los cambios clave para las partículas:
| Godot 3 | Godot 4 | Notas |
|---|---|---|
Particles2D |
GPUParticles2D |
Renombrado |
Particles (3D) |
GPUParticles3D |
Renombrado |
ParticlesMaterial |
ParticleProcessMaterial |
Renombrado con nuevas funciones |
CPUParticles2D |
CPUParticles2D |
Sin cambios |
CPUParticles |
CPUParticles3D |
Renombrado para mayor claridad |
| Sin sub-emisores | sub_emitter_mode |
Nuevo en Godot 4 |
| Sin estelas | trail_enabled |
Nuevo en Godot 4 |
flag_align_y |
particle_flag_align_y |
Propiedad renombrada |
ParticlesMaterial en GDScript deberá actualizarse manualmente a ParticleProcessMaterial.
Automatiza efectos de partículas con MCP Pro
¿Quieres que la IA cree efectos de partículas por ti? Godot MCP Pro incluye herramientas de partículas dedicadas con presets para fuego, humo, lluvia, nieve, chispas y mucho más. Control total sobre materiales, gradientes y formas de emisión desde una sola conversación.
- create_particles
- set_particle_material
- set_particle_color_gradient
- apply_particle_preset
- get_particle_info