强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Godot 4 GDScript 教程 / 粒子系统(GPUParticles)

粒子系统(GPUParticles)

概述

Godot 4 使用 GPU 加速粒子系统 GPUParticles3D/2D 替代了 Godot 3 中的 CPUParticles,性能大幅提升。粒子通过 ParticleProcessMaterial 配置行为,支持碰撞、吸引子和自定义着色器。

节点说明
GPUParticles3D3D GPU 粒子
GPUParticles2D2D GPU 粒子
CPUParticles3D3D CPU 粒子(兼容设备)
CPUParticles2D2D CPU 粒子(兼容设备)

⚠️ 注意:GPUParticles 需要支持 Vulkan/OpenGL 3.3+ 的显卡。如果目标平台性能较差,考虑使用 CPUParticles。


GPUParticles3D 基础

基本设置

extends GPUParticles3D

func _ready():
    # 粒子数量
    amount = 100
    # 粒子生命周期(秒)
    lifetime = 2.0
    # 一次性发射(不循环)
    one_shot = false
    # 发射速度预热
    preprocess = 0.5
    # 爆发式发射
    explosiveness = 0.0  # 0 = 持续发射,1 = 同时发射
    # 随机化
    randomness = 0.5
    # 是否发射
    emitting = true
    # 固定 FPS
    fixed_fps = 30

ParticleProcessMaterial

粒子材质控制粒子的所有行为参数。

代码创建粒子材质

extends GPUParticles3D

func _ready():
    var mat = ParticleProcessMaterial.new()

    # 发射方向
    mat.direction = Vector3(0, 1, 0)
    mat.spread = 45.0  # 扩散角度

    # 初始速度
    mat.initial_velocity_min = 2.0
    mat.initial_velocity_max = 5.0

    # 重力
    mat.gravity = Vector3(0, -9.8, 0)

    # 缩放
    mat.scale_min = 0.1
    mat.scale_max = 0.3

    # 颜色渐变
    var gradient = Gradient.new()
    gradient.set_color(0, Color(1, 0.8, 0.2, 1))  # 起始:橙色
    gradient.set_color(1, Color(1, 0.2, 0, 0))     # 结束:透明红
    mat.color_ramp = gradient

    # 角速度
    mat.angular_velocity_min = -180.0
    mat.angular_velocity_max = 180.0

    # 阻尼(减速)
    mat.damping_min = 1.0
    mat.damping_max = 3.0

    process_material = mat
    amount = 200
    lifetime = 3.0

材质参数速查表

参数说明
direction发射方向
spread扩散角度(度)
initial_velocity_min/max初始速度范围
gravity重力向量
scale_min/max缩放范围
color颜色
color_ramp颜色渐变曲线
alpha_curve透明度曲线
damping_min/max阻尼(减速)
angular_velocity_min/max角速度
linear_accel_min/max线性加速度
radial_accel_min/max径向加速度
tangential_accel_min/max切线加速度
orbit_min/max轨道运动

发射形状

extends GPUParticles3D

func _ready():
    var mat = ParticleProcessMaterial.new()

    # 发射形状
    mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
    mat.emission_sphere_radius = 1.0

    # 其他形状选项
    # EMISSION_SHAPE_POINT      — 点发射
    # EMISSION_SHAPE_SPHERE     — 球体表面
    # EMISSION_SHAPE_SPHERE_VOLUME — 球体体积
    # EMISSION_SHAPE_BOX        — 盒子
    # EMISSION_SHAPE_RING       — 环形
    # EMISSION_SHAPE_DIRECTED_POINTS — 指向性点阵

    process_material = mat
形状适用场景
POINT集中一点发射(火焰)
SPHERE球形扩散(爆炸)
BOX区域内随机(灰尘、雨)
RING环形发射(光环)
DIRECTED_POINTS沿表面法线发射(毛发)

粒子碰撞

extends GPUParticles3D

func _ready():
    # 启用粒子碰撞
    collision_mode = GPUParticles3D.COLLISION_RIGID
    # 碰撞弹力
    # 通过 ParticleProcessMaterial 的 collision 实现

碰撞高度场

# 添加 GPUParticlesCollisionHeightField3D 节点到场景
# 它会将场景渲染为高度场供粒子碰撞

# 代码中设置
var height_field = GPUParticlesCollisionHeightField3D.new()
height_field.size = Vector3(50, 20, 50)
add_child(height_field)

吸引子 Attractor3D

# GPUParticlesAttractorBox3D — 盒形吸引子
# GPUParticlesAttractorSphere3D — 球形吸引子
# GPUParticlesAttractorVectorField3D — 向量场吸引子

extends GPUParticlesAttractorSphere3D

func _ready():
    # 吸引力强度(负值 = 排斥)
    strength = 10.0
    # 影响半径
    # 通过 size 或 radius 设置
    # 衰减
    attenuation = 2.0  # 距离衰减指数

粒子动画

使用纹理帧动画

extends GPUParticles3D

func _ready():
    var mat = ParticleProcessMaterial.new()
    # 粒子动画:精灵表(Spritesheet)
    # 在 ParticleProcessMaterial 中设置
    # 或在着色器中处理 UV 动画
    process_material = mat

    # 设置 Draw Pass 的 QuadMesh 纹理
    var mesh = QuadMesh.new()
    mesh.size = Vector2(0.5, 0.5)
    draw_pass_1 = mesh

火焰效果实战

extends GPUParticles3D

func _ready():
    amount = 150
    lifetime = 1.5
    explosiveness = 0.0
    amount_ratio = 1.0

    var mat = ParticleProcessMaterial.new()
    mat.direction = Vector3(0, 1, 0)
    mat.spread = 15.0
    mat.initial_velocity_min = 3.0
    mat.initial_velocity_max = 5.0
    mat.gravity = Vector3(0, 0.5, 0)  # 热气上升
    mat.scale_min = 0.3
    mat.scale_max = 0.8
    mat.damping_min = 2.0
    mat.damping_max = 4.0

    # 颜色:黄 → 橙 → 红 → 透明
    var gradient = Gradient.new()
    gradient.set_color(0, Color(1, 1, 0.5, 1))
    gradient.set_color(0.3, Color(1, 0.6, 0.1, 0.8))
    gradient.set_color(0.7, Color(0.8, 0.2, 0, 0.4))
    gradient.set_color(1, Color(0.3, 0.1, 0, 0))
    mat.color_ramp = gradient

    # 发射形状
    mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
    mat.emission_sphere_radius = 0.2

    process_material = mat

烟雾效果实战

extends GPUParticles3D

func _ready():
    amount = 80
    lifetime = 4.0

    var mat = ParticleProcessMaterial.new()
    mat.direction = Vector3(0, 1, 0)
    mat.spread = 30.0
    mat.initial_velocity_min = 1.0
    mat.initial_velocity_max = 2.5
    mat.gravity = Vector3(0, 1.5, 0)  # 烟雾上升
    mat.scale_min = 0.5
    mat.scale_max = 1.5
    mat.damping_min = 0.5
    mat.damping_max = 1.0

    # 横向漂移
    mat.linear_accel_min = -0.5
    mat.linear_accel_max = 0.5

    # 灰色渐变
    var gradient = Gradient.new()
    gradient.set_color(0, Color(0.4, 0.4, 0.4, 0.3))
    gradient.set_color(1, Color(0.2, 0.2, 0.2, 0))
    mat.color_ramp = gradient

    mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
    mat.emission_sphere_radius = 0.3

    process_material = mat

爆炸效果实战

extends Node3D

@onready var particles: GPUParticles3D = $GPUParticles3D
@onready var debris: GPUParticles3D = $DebrisParticles

func explode():
    # 火焰爆发
    particles.amount = 300
    particles.lifetime = 1.0
    particles.explosiveness = 1.0  # 瞬间全部发射
    particles.one_shot = true
    particles.restart()

    # 碎片飞溅
    debris.amount = 50
    debris.lifetime = 2.0
    debris.explosiveness = 1.0
    debris.one_shot = true

    var mat = ParticleProcessMaterial.new()
    mat.direction = Vector3(0, 1, 0)
    mat.spread = 180.0
    mat.initial_velocity_min = 5.0
    mat.initial_velocity_max = 15.0
    mat.gravity = Vector3(0, -15, 0)
    mat.damping_min = 0.5
    mat.damping_max = 1.5
    debris.process_material = mat
    debris.restart()

    # 延迟销毁
    await get_tree().create_timer(3.0).timeout
    queue_free()

粒子性能优化

策略说明
减少粒子数量能用 50 个就不用 100 个
使用 LOD远处减少/禁用粒子
降低 fixed_fps设为 15~30 足够
使用 visibility_aabb不可见时停止计算
合理设置 lifetime短生命周期减少同时存在数
用 CPUParticles 兜底低端设备兼容
extends GPUParticles3D

func _ready():
    # 设置可见性 AABB(剔除区域)
    visibility_aabb = AABB(Vector3(-5, -5, -5), Vector3(10, 10, 10))
    # 超出视锥时不计算

💡 提示:如果粒子效果不明显,尝试增大粒子尺寸或调整颜色对比度,而非盲目增加数量。


自定义粒子着色器

# 使用 ShaderMaterial 替代 ParticleProcessMaterial
extends GPUParticles3D

func _ready():
    var shader_mat = ShaderMaterial.new()
    shader_mat.shader = preload("res://shaders/custom_particle.gdshader")
    process_material = shader_mat
// custom_particle.gdshader — 粒子着色器
shader_type particles;

uniform float speed_mult = 1.0;

void start() {
    // 初始化粒子
    VELOCITY = (EMISSION_TRANSFORM * vec4(0.0, 1.0, 0.0, 0.0)).xyz * speed_mult;
    CUSTOM.x = 0.0; // 自定义数据
}

void process() {
    // 每帧更新
    CUSTOM.x += DELTA / LIFETIME; // 0~1 生命周期进度
    VELOCITY.y -= 9.8 * DELTA;    // 自定义重力

    if (CUSTOM.x >= 1.0) {
        ACTIVE = false; // 粒子死亡
    }
}

2D 粒子

extends GPUParticles2D

func _ready():
    amount = 100
    lifetime = 2.0

    var mat = ParticleProcessMaterial.new()
    mat.direction = Vector3(0, -1, 0)  # 向上
    mat.spread = 30.0
    mat.initial_velocity_min = 50.0
    mat.initial_velocity_max = 100.0
    mat.gravity = Vector3(0, 200, 0)   # 2D 向下重力
    mat.scale_min = 0.5
    mat.scale_max = 1.5

    var gradient = Gradient.new()
    gradient.set_color(0, Color(1, 1, 1, 1))
    gradient.set_color(1, Color(1, 1, 1, 0))
    mat.color_ramp = gradient

    process_material = mat

游戏开发场景

场景粒子类型参数要点
火把火焰GPUParticles3D黄→红渐变,上升方向
爆炸GPUParticles3D爆发式,180° 扩散
烟雾GPUParticles3D缓慢上升,大尺寸
下雨GPUParticles2DBox 发射,高速下落
魔法特效GPUParticles3D自定义着色器 + 发光
落叶GPUParticles2D随机漂移,旋转
粒尘/脚印GPUParticles3D小尺寸,短生命周期

⚠️ 常见陷阱

  1. GPUParticles 需要 Vulkan/OpenGL 3.3+,低端设备用 CPUParticles
  2. one_shot = true 后需要 restart() 重新发射
  3. explosiveness = 1.0 表示一次性发射所有粒子,不是瞬间完成
  4. 粒子材质的重力方向是 Vector3,2D 也用 Vector3(忽略 z)
  5. 大量粒子会严重影响性能,注意监控 FPS

扩展阅读