~2 мин чтения

Частицы — GPUParticles3D и CPUParticles3D

ParticleProcessMaterial, эмиттеры, sub-emitters, collision.

В Godot два узла для частиц с похожим API:

  • GPUParticles3D — на GPU, до миллионов частиц.
  • CPUParticles3D — на CPU, fallback для слабого железа и веба.
ПараметрGPUParticles3DCPUParticles3D
Где вычисляетсяGPU (compute)CPU
Максимум частицМиллионы~10 000
Compatibility-рендерРаботают с оговорками (требуется compute)Работают везде
Web-цельОграниченно (зависит от WebGL)Работают
Per-particle GDScript-доступНетДа

Грубое правило: GPU где можно, CPU где обязательно.

ParticleProcessMaterial

Главное отличие от Unity Particle System: поведение частиц задаётся не в инспекторе узла, а в отдельном ресурсе ParticleProcessMaterial. Это удобно — можно сохранить, переиспользовать, override в инстансах.

@onready var particles: GPUParticles3D = $GPUParticles3D

func _ready() -> void:
    var mat: ParticleProcessMaterial = particles.process_material
    mat.initial_velocity_min = 5.0
    mat.initial_velocity_max = 10.0
    mat.gravity = Vector3(0, -3, 0)

Главные секции ParticleProcessMaterial:

  • Direction + spread — направление выброса.
  • Initial Velocity (min/max) — стартовая скорость.
  • Gravity — на каждую частицу.
  • Linear / Angular / Radial Accel — постоянные ускорения.
  • Damping — гашение скорости.
  • Color + Color Curve — цвет и кривая по жизни.
  • Scale + Scale Curve — размер.
  • Hue Variation, Anim Speed / Offset — для текстурных листов.
  • Emission ShapePOINT, SPHERE, BOX, POINTS, DIRECTED_POINTS, RING.

GPUParticles3D — узел

Главные свойства на самом узле:

  • amount — максимальное число одновременных частиц.
  • lifetime — время жизни в секундах.
  • one_shot — одноразовый выстрел или непрерывный.
  • explosiveness — 0..1, насколько “залпом” вылетают (0 = равномерно, 1 = все одновременно).
  • emitting — испускать сейчас.
  • fixed_fps — фиксированная частота обновления (0 = с FPS).
  • local_coords — позиции частиц локальные или мировые.
# Запуск одноразового взрыва
func boom(at: Vector3) -> void:
    var explosion = explosion_scene.instantiate()
    explosion.global_position = at
    get_tree().current_scene.add_child(explosion)
    explosion.emitting = true  # включить эмиссию

# Автоудаление
func _on_finished() -> void:
    queue_free()

Сигнал finished срабатывает после lifetime (для one_shot = true).

Trails (следы)

Каждая частица может оставлять trail — узкую ленту, идущую за ней:

  • trail_enabled = true на узле GPUParticles3D.
  • trail_lifetime — длина следа в секундах.
  • Mesh trail (если хотите кастомный mesh) — через draw_pass_1.mesh.

Полезно для пуль-трассеров, спецэффектов магии.

Sub-emitters

GPUParticles3D могут испускать другие частицы при определённых событиях:

Explosion (GPUParticles3D — главный)
└── SubEmitter (GPUParticles3D — sub)

Виды sub-emitter activation:

  • CONSTANT — постоянно от каждой родительской частицы.
  • AT_END — в момент смерти родителя.
  • AT_COLLISION — при касании коллайдера (требует collision_enabled).

Пример: ракета (родительская частица) — при касании земли испускает 50 искр (sub-emitter).

Collision с миром

Чтобы частицы реагировали на коллизии:

  1. ParticleProcessMaterial.collision_mode = COLLISION_RIGID (отскакивают) или COLLISION_HIDE_ON_CONTACT.
  2. Добавьте на сцену GPUParticlesCollisionSphere3D, GPUParticlesCollisionBox3D, GPUParticlesCollisionHeightField3D или GPUParticlesCollisionSDF3D — это специальные коллайдеры только для частиц, отдельные от физических.
Collision с обычной физикой — нет

GPU-частицы НЕ сталкиваются с обычными StaticBody3D / Collider’ами. Они используют отдельную систему GPUParticlesCollision* узлов. Это сделано для производительности GPU-симуляции.

Visibility AABB

GPUParticles3D имеют visibility_aabb — bounding box, в пределах которого они считаются видимыми. Если AABB вне камеры — частицы не симулируются.

По умолчанию AABB маленький (вокруг эмиттера) и частицы, улетевшие далеко, могут “пропадать”. Решение: вручную задать большой AABB или нажать Generate AABB в редакторе (Godot подберёт по симуляции).

particles.visibility_aabb = AABB(Vector3(-20, -20, -20), Vector3(40, 40, 40))

ProcessMaterial vs ShaderMaterial для частиц

ParticleProcessMaterial — стандартный, покрывает 90% задач. Если нужно нестандартное поведение (specific вихрь, attractor по сложной формуле), пишите свой ShaderMaterial с shader_type particles:

shader_type particles;
render_mode keep_data;

uniform vec3 swirl_center;
uniform float swirl_strength;

void process() {
    vec3 to_center = swirl_center - TRANSFORM[3].xyz;
    float dist = length(to_center);
    vec3 tangent = normalize(cross(to_center, vec3(0, 1, 0)));
    VELOCITY += tangent * swirl_strength * (1.0 / max(dist, 0.5));
    TRANSFORM[3].xyz += VELOCITY * DELTA;
}

Это процессинг-шейдер. Рендерится частица отдельным draw pass материалом (через draw_pass_1 на GPUParticles3D).

CPUParticles3D — когда полезно

  • Web-сборка с Compatibility-рендером — GPU-симуляция там работает не везде (особенно на WebGL без compute).
  • Per-particle логика на GDScript — если хотите менять отдельные частицы в коде.
  • Старое железо, где compute shader недоступен.

API почти идентично, но настройки — прямо на узле (без отдельного ProcessMaterial).

Профайлинг

GPU-частицы — одна из самых нагружающих фич. В Debugger → Profiler → Visual смотрите время prepare/process. Если 10000+ частиц на слабом телефоне — режьте amount и lifetime.

В следующей главе — мультиплеер.