GPUParticles2D/3D trong Godot 4 — Hướng dẫn đầy đủ
1. Giới thiệu
Godot 4 sử dụng GPUParticles2D và GPUParticles3D làm các node hệ thống particle mặc định. Chúng chạy hoàn toàn trên GPU, do đó nhanh hơn đáng kể so với các phiên bản CPU khi xử lý số lượng particle lớn. ParticlesMaterial cũ từ Godot 3 đã được thay thế bằng ParticleProcessMaterial, cung cấp khả năng kiểm soát hành vi particle nhiều hơn.
CPUParticles2D và CPUParticles3D vẫn tồn tại như các node dự phòng cho những thiết bị không hỗ trợ GPU compute, hoặc khi bạn cần truy cập dữ liệu của từng particle riêng lẻ từ GDScript. Trong hầu hết các trường hợp, particle GPU là lựa chọn được khuyến nghị.
2. GPUParticles2D vs. CPUParticles2D
| Đặc điểm | GPUParticles2D | CPUParticles2D |
|---|---|---|
| Xử lý | GPU (compute shader) | CPU (luồng chính) |
| Số particle tối đa | 100.000+ vẫn hiệu quả | ~1.000-5.000 là giới hạn thực tế |
| Sub-emitter | Có | Không |
| Trail | Có | Không |
| Truy cập từng particle | Không (chỉ GPU) | Có (từ GDScript) |
| Chế độ tương thích | Yêu cầu Vulkan/Metal/D3D12 | Hoạt động ở mọi nơi |
| Loại material | ParticleProcessMaterial | Thuộc tính tích hợp sẵn (không cần material) |
GPUParticles2D. Chỉ chuyển sang CPUParticles2D khi bạn cần hỗ trợ trình render Compatibility, cần đọc vị trí particle trong GDScript, hoặc nhắm tới phần cứng rất cũ.
3. Thiết lập cơ bản
Để tạo một hiệu ứng particle cơ bản, hãy thêm một node GPUParticles2D vào scene của bạn và gán cho nó một ParticleProcessMaterial. Dưới đây là thiết lập tối giản bằng 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)
Các thuộc tính quan trọng trên chính node GPUParticles2D:
amount— Số particle tồn tại đồng thời tại một thời điểm (mặc định: 8)lifetime— Thời gian sống của mỗi particle tính bằng giây (mặc định: 1.0)one_shot— Phát ra một lần rồi dừng (mặc định: false)explosiveness— 0.0 = dòng liên tục, 1.0 = tất cả particle cùng một lúcrandomness— Độ lệch ngẫu nhiên cho thời điểm phát (0.0-1.0)speed_scale— Hệ số nhân cho tốc độ mô phỏngemitting— Hệ thống có đang phát particle hay không
4. Tìm hiểu sâu ParticleProcessMaterial
ParticleProcessMaterial điều khiển cách từng particle hành xử trong suốt vòng đời của nó. Tất cả các thuộc tính về hướng đều dùng Vector3, ngay cả với particle 2D (thành phần Z chỉ đơn giản là bị bỏ qua).
Hướng & Vận tốc
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
Vận tốc góc
Làm particle xoay tròn khi di chuyển. Hữu ích cho mảnh vỡ, hoa giấy hoặc lá cây.
mat.angular_velocity_min = -180.0 # degrees per second mat.angular_velocity_max = 180.0
Thay đổi tỷ lệ theo vòng đời
Sử dụng CurveTexture để thay đổi kích thước particle theo vòng đời của nó:
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
Damping & Attractor
Damping làm particle chậm lại theo thời gian, mô phỏng lực cản không khí. Attractor (các node riêng biệt) kéo particle về phía một điểm.
mat.damping_min = 5.0 mat.damping_max = 10.0
5. Dải màu chuyển sắc
Thuộc tính color_ramp trên ParticleProcessMaterial nhận một GradientTexture1D để thay đổi mượt mà màu sắc particle theo vòng đời. Điều này rất cần thiết cho các hiệu ứng lửa, khói và ma thuật chân thực.
Ví dụ: Dải màu lửa
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
Với particle đơn sắc, bạn cũng có thể đặt một thuộc tính color phẳng thay vì dải màu chuyển sắc:
mat.color = Color(0.2, 0.6, 1.0, 0.8) # Semi-transparent blue
6. Hình dạng emission
Hình dạng emission xác định nơi particle được sinh ra. Được thiết lập qua emission_shape trên ParticleProcessMaterial.
Point
Tất cả particle sinh ra tại gốc tọa độ của node. Đây là hình dạng mặc định.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_POINT
Sphere / Sphere Surface
Particle sinh ra ngẫu nhiên bên trong một hình cầu (hoặc chỉ trên bề mặt của nó).
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
Particle sinh ra ngẫu nhiên bên trong một khối hình hộp chữ nhật.
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX mat.emission_box_extents = Vector3(100, 10, 0) # Wide and thin
Ring
Particle sinh ra theo hình vòng (donut), được xác định bởi bán kính trong/ngoài và chiều cao.
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 với chiều X rộng và chiều Y hẹp để tạo các hiệu ứng sát mặt đất như vệt bụi hoặc particle bước chân.
7. Công thức thực tế
Lửa
Dải màu cam-đỏ, vận tốc hướng lên, độ tỏa nhẹ, tỷ lệ giảm dần theo vòng đời.
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
Khói
Dải màu xám, chuyển động đi lên chậm, độ tỏa lớn, alpha thấp để tạo vẻ mờ ảo.
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
Mưa
Các vệt xanh-trắng, trọng lực hướng xuống mạnh, độ tỏa hẹp, số lượng particle lớn.
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
Tia lửa
Vàng-cam, bùng phát dữ dội, vận tốc ban đầu cao, vòng đời ngắn.
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
Tuyết
Particle trắng, rơi xuống chậm và nhẹ nhàng, độ tỏa rộng, hơi trôi ngang.
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. Particle 3D (GPUParticles3D)
GPUParticles3D hoạt động giống hệt GPUParticles2D nhưng vận hành trong không gian 3D. Nó vẫn dùng cùng một ParticleProcessMaterial. Những điểm khác biệt chính:
- Cả 3 trục của
Vector3đều hoạt động (X, Y, Z) - Hình dạng emission hoạt động trong 3D đầy đủ (hình cầu là hình cầu thật, hộp là khối thể tích)
- Bạn có thể dùng
draw_pass_1với mộtQuadMeshhoặc mesh tùy chỉnh cho particle dạng billboard - Particle dạng mesh có thể dùng
StandardMaterial3DhoặcORMMaterial3D
# 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 tùy chỉnh cho draw_pass_1 và áp dụng một StandardMaterial3D lên nó. Mỗi particle sẽ được render như một bản sao của mesh đó.
9. Sub-emitter
Godot 4 hỗ trợ sub-emitter cho các hiệu ứng particle-sinh-particle. Sub-emitter là một node GPUParticles2D/GPUParticles3D khác, phát ra particle tại vị trí của mỗi particle cha. Điều này lý tưởng cho:
- Tia lửa bắn ra từ particle lửa
- Vệt khói phía sau vụ nổ pháo hoa
- Giọt nước bắn tóe khi va chạm
- Vụ nổ thứ cấp
Cách thiết lập 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)
Các chế độ sub-emitter:
SUB_EMITTER_CONSTANT— Phát liên tục từ mỗi particle chaSUB_EMITTER_AT_END— Phát khi particle cha kết thúc vòng đờiSUB_EMITTER_AT_COLLISION— Phát khi particle cha va chạm
GPUParticles, không hoạt động với CPUParticles. Mỗi sub-emitter làm tăng tải GPU, vì vậy hãy giữ số lượng particle của sub-emitter ở mức thấp (4-8 mỗi particle cha).
10. Mẹo tối ưu hiệu năng
-
Cân bằng giữa Số lượng và Vòng đời:
Tổng số particle hiển thị =
amount. Nếu bạn tănglifetime, particle sẽ tích tụ lâu hơn. Giảmamountđể bù lại, hoặc tăng nó để có hiệu ứng dày đặc hơn. -
Dùng Visibility Range (3D):
Đặt
visibility_range_endtrên GPUParticles3D để các hệ thống particle ở xa ngừng được render. Đây là lợi ích lớn cho thế giới mở. -
FPS cố định:
Đặt
fixed_fpstrên node particle (ví dụ 30) để giới hạn số lần cập nhật mô phỏng. Particle vẫn được nội suy mượt mà nhưng dùng ít thời gian GPU hơn. -
One-shot cho các cú bùng phát:
Với các hiệu ứng kiểu vụ nổ, hãy dùng
one_shot = truecùngexplosiveness = 1.0. Node sau đó có thể được giải phóng khi hết vòng đời. -
Dùng LOD cho 3D:
Kết hợp
visibility_range_begin/endvới nhiều node particle ở các mức chi tiết khác nhau để tạo hiệu ứng particle theo mức độ chi tiết (LOD). -
Tránh overdraw:
Nhiều particle bán trong suốt chồng lên nhau = fill rate tốn kém. Hãy giảm
amountvà thay vào đó dùng particle lớn hơn với alpha thấp hơn.
11. Chuyển đổi từ Godot 3 sang 4
Nếu bạn đang chuyển một dự án từ Godot 3 sang Godot 4, dưới đây là những thay đổi quan trọng nhất về particle:
| Godot 3 | Godot 4 | Ghi chú |
|---|---|---|
Particles2D |
GPUParticles2D |
Đổi tên |
Particles (3D) |
GPUParticles3D |
Đổi tên |
ParticlesMaterial |
ParticleProcessMaterial |
Đổi tên kèm tính năng mới |
CPUParticles2D |
CPUParticles2D |
Không đổi |
CPUParticles |
CPUParticles3D |
Đổi tên cho rõ ràng |
| No sub-emitters | sub_emitter_mode |
Mới trong Godot 4 |
| No trails | trail_enabled |
Mới trong Godot 4 |
flag_align_y |
particle_flag_align_y |
Đổi tên thuộc tính |
ParticlesMaterial trong GDScript cần được cập nhật thủ công thành ParticleProcessMaterial.
Tự động hóa hiệu ứng particle với MCP Pro
Bạn muốn AI tạo hiệu ứng particle giúp bạn? Godot MCP Pro bao gồm các công cụ particle chuyên dụng với preset cho lửa, khói, mưa, tuyết, tia lửa và nhiều hơn nữa. Toàn quyền kiểm soát material, dải màu chuyển sắc và hình dạng emission chỉ trong một cuộc trò chuyện.
- create_particles
- set_particle_material
- set_particle_color_gradient
- apply_particle_preset
- get_particle_info