GPUParticles2D/3D в Godot 4 — Полное руководство
1. Введение
Godot 4 использует GPUParticles2D и GPUParticles3D в качестве стандартных узлов системы частиц. Они полностью работают на GPU, что делает их значительно быстрее их аналогов на CPU при большом количестве частиц. Старый ParticlesMaterial из Godot 3 был заменён на ParticleProcessMaterial, который даёт больше контроля над поведением частиц.
CPUParticles2D и CPUParticles3D по-прежнему существуют как резервные узлы для устройств без поддержки GPU-вычислений или когда вам нужно обращаться к данным отдельных частиц из GDScript. Для большинства случаев рекомендуется выбирать частицы на GPU.
2. GPUParticles2D против CPUParticles2D
| Характеристика | GPUParticles2D | CPUParticles2D |
|---|---|---|
| Обработка | GPU (compute-шейдер) | CPU (основной поток) |
| Макс. частиц | 100 000+ эффективно | ~1 000-5 000 практический предел |
| Суб-эмиттеры | Да | Нет |
| Трейлы | Да | Нет |
| Доступ к отдельным частицам | Нет (только GPU) | Да (из GDScript) |
| Режим совместимости | Требует Vulkan/Metal/D3D12 | Работает везде |
| Тип материала | ParticleProcessMaterial | Встроенные свойства (без материала) |
GPUParticles2D по умолчанию. Переключайтесь на CPUParticles2D только если вам нужна поддержка рендерера Compatibility, требуется читать позиции частиц в GDScript или вы ориентируетесь на очень старое оборудование.
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. Цветовые градиенты
Свойство color_ramp у ParticleProcessMaterial принимает 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. Формы эмиссии
Форма эмиссии определяет, где появляются частицы. Задаётся через emission_shape у ParticleProcessMaterial.
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. Ключевые отличия:
- Все 3 оси
Vector3активны (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)
draw_pass_1 собственный меш .tres и примените к нему 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. Советы по производительности
-
Компромисс количества и времени жизни:
Всего видимых частиц =
amount. Если вы увеличиваетеlifetime, частицы накапливаются дольше. Уменьшитеamountдля компенсации или увеличьте его для более плотных эффектов. -
Используйте Visibility Range (3D):
Задайте
visibility_range_endу GPUParticles3D, чтобы удалённые системы частиц перестали отрисовываться. Это большой выигрыш для открытых миров. -
Фиксированный FPS:
Задайте
fixed_fpsу узла частиц (например, 30), чтобы ограничить обновления симуляции. Частицы по-прежнему будут плавно интерполироваться, но потребуют меньше времени GPU. -
One-shot для всплесков:
Для взрывоподобных эффектов используйте
one_shot = trueсexplosiveness = 1.0. Узел затем можно освободить после окончания времени жизни. -
Используйте LOD для 3D:
Сочетайте
visibility_range_begin/endс несколькими узлами частиц на разных уровнях детализации для LOD-эффектов частиц (Level of Detail). -
Избегайте overdraw:
Множество перекрывающихся полупрозрачных частиц = дорогая fill rate. Уменьшите
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 в GDScript нужно будет вручную обновить на ParticleProcessMaterial.
Автоматизируйте эффекты частиц с MCP Pro
Хотите, чтобы ИИ создавал эффекты частиц за вас? Godot MCP Pro включает специальные инструменты для частиц с пресетами для огня, дыма, дождя, снега, искр и не только. Полный контроль над материалами, градиентами и формами эмиссии из одного разговора.
- create_particles
- set_particle_material
- set_particle_color_gradient
- apply_particle_preset
- get_particle_info