Partículas 3D no Godot 4: Fumaça, Fogo e Faíscas com GPUParticles3D

Partículas 3D no Godot 4 na prática: crie fumaça, fogo, faíscas e poeira com GPUParticles3D, ProcessMaterial e código tipado, do zero ao disparo por script.
O que são partículas 3D no Godot e por que usar
Partículas 3D no Godot são milhares de pequenos elementos que nascem, se movem no espaço, mudam de cor e tamanho e morrem sozinhos, tudo controlado por um único node. Em vez de animar cada baforada de fumaça ou cada faísca à mão, você define regras (direção, velocidade, gravidade, tempo de vida) e o motor gera as cópias seguindo essas regras dentro da sua cena 3D. É assim que se faz fumaça de fogueira, chama de tocha, faíscas de golpe, poeira de pouso, jato de propulsor e névoa mágica sem modelar nada frame por frame.
No Godot 4 o node principal para isso é o GPUParticles3D, e é nele que este guia foca. Vou mostrar como criar o node, como o ParticleProcessMaterial dá vida às partículas, como o Draw Pass usa uma mesh para desenhar cada partícula, como controlar emissão, gravidade, velocidade, escala e cor ao longo da vida, a diferença entre disparo único e contínuo, como acionar tudo por GDScript tipado e quando faz sentido trocar pelo CPUParticles3D. Se você veio do 2D, o raciocínio é o mesmo do par partículas 2D com GPUParticles2D; a novidade aqui é a mesh do draw pass e a terceira dimensão.
Criando o GPUParticles3D na cena
Na sua cena 3D, adicione um node GPUParticles3D (Add Node, procure por GPUParticles3D). Ao selecionar o node novo você vai reparar que nada acontece na viewport, e isso é esperado: recém-criado, o node não tem material de processo nem mesh para desenhar. São dois campos obrigatórios no inspetor:
- Process Material. É onde mora todo o comportamento (para onde as partículas vão, quão rápido, com que cor). Precisa ser um
ParticleProcessMaterial. - Draw Passes → Pass 1. É a mesh que representa cada partícula visualmente. Sem ela o efeito é invisível.
No próprio node ficam três valores que você mexe o tempo todo: amount (quantas partículas existem ao mesmo tempo), lifetime (quantos segundos cada uma vive) e emitting (se está emitindo agora ou não). Comece com amount em 16 e lifetime em 2.0 só para ver algo se mexer, e vá ajustando.
O ParticleProcessMaterial: onde mora o comportamento
Clique em Process Material e crie um New ParticleProcessMaterial. Esse recurso é o cérebro do efeito. Vale conhecer os grupos que você mais usa:
Emission Shape (forma de emissão). De onde as partículas nascem. O padrão é EMISSION_SHAPE_POINT, um único ponto. Você pode trocar por esfera ou caixa (emission_shape) para espalhar o nascimento numa área, ótimo para fumaça larga ou poeira num raio.
Direction e Spread (direção e abertura). O vetor direction aponta para onde as partículas seguem (por exemplo Vector3(0, 1, 0) para cima) e o spread, em graus, controla o quanto elas abrem em relação a essa direção. Spread 0 lança tudo reto; spread 180 joga para todos os lados, ideal para explosão.
Gravity (gravidade). Um Vector3 que puxa as partículas continuamente. Para faíscas caindo, deixe algo como Vector3(0, -9.8, 0). Para fumaça subindo, inverta e use um Y positivo pequeno, tipo Vector3(0, 0.8, 0).
Initial Velocity (velocidade inicial). A força com que cada partícula sai, com initial_velocity_min e initial_velocity_max. Como cada partícula sorteia um valor na faixa, você evita aquele visual robótico de tudo igual.
Scale (escala ao longo da vida). scale_min e scale_max dão o tamanho inicial, e a scale_curve permite crescer ou encolher durante o lifetime. Fumaça que incha ao subir e explosão que estoura e some saem daqui.
Color e Color Ramp (cor ao longo da vida). Você pode dar uma cor fixa em color ou, muito melhor, um Gradient em color_ramp. A partícula percorre esse gradiente durante toda a vida. Fogo que vai de amarelo para vermelho e some, fumaça de cinza claro para transparente: tudo é o gradiente. Deixar o alpha caindo para zero no fim faz a partícula desaparecer suave em vez de piscar.
O Draw Pass: a mesh que você vê
Essa é a grande diferença para o 2D. No 3D, cada partícula é desenhada usando uma mesh, definida em Draw Passes. Sem uma mesh no Pass 1, o GPUParticles3D emite mas você não vê nada.
Para fumaça, fogo e faíscas, o padrão é usar um QuadMesh (um retângulo plano barato) com um StandardMaterial3D configurado como billboard, para o quad sempre encarar a câmera, mais uma textura com transparência. No material da mesh, ligue Billboard como BILLBOARD_ENABLED e Transparency para usar o alpha da textura. Assim cada partícula parece uma baforada ou uma centelha, e não um cartão plano visto de lado.
Para detritos, pedras ou estilhaços que devem ter volume real, use uma mesh sólida como BoxMesh ou SphereMesh pequena no draw pass. Regra prática: efeito de luz, fogo e fumaça pedem QuadMesh com billboard; pedaço físico pede mesh sólida.
one_shot vs contínuo: rajada ou fluxo
A propriedade one_shot do node decide o ritmo da emissão, e entender isso separa um efeito que funciona de um travado em loop.
Com one_shot desligado (o padrão), a emissão é contínua. O node fica soltando partículas em loop enquanto emitting estiver ligado. É o certo para fogo de tocha, fumaça de chaminé, jato de propulsor, brilho de item mágico, qualquer coisa que dura.
Com one_shot ligado, o node solta um lote de partículas de uma vez e para. É o comportamento de explosão, poeira de pouso, respingo, faísca de impacto: um evento único disparado num instante. Depois de soltar o lote, o emitting volta sozinho para false.
Explosão e faísca: sempre one_shot ligado. Fumaça e fogo contínuos: one_shot desligado.
Disparar partículas 3D por código
Aqui entra o GDScript tipado. Você raramente deixa o efeito emitindo desde o início; normalmente dispara no momento exato do evento. Duas ferramentas resolvem quase tudo:
emitting = true/emitting = falseliga e desliga a emissão contínua.restart()reinicia a emissão do zero, a forma correta de disparar umone_shot.
Referencie o node com @onready tipado para o código ficar seguro e legível:
extends Node3D
@onready var fumaca: GPUParticles3D = $Fumaca
@onready var explosao: GPUParticles3D = $Explosao
func _ready() -> void:
# fumaca comeca ligada e continua; explosao fica em espera
fumaca.emitting = true
explosao.emitting = false
func disparar_explosao() -> void:
# one_shot ligado no inspetor: restart() solta o lote uma vez
explosao.restart()
O restart() é importante porque, num one_shot, só setar emitting = true pode não redisparar se o efeito já rodou uma vez. O restart() zera o estado interno e garante a nova rajada toda vez que você chama.
Receita 1: explosão com one_shot
Crie um GPUParticles3D, atribua um ParticleProcessMaterial e um QuadMesh billboard no draw pass, e no inspetor:
one_shot: ligadoamount: 32lifetime: 0.7emitting: desligado (só dispara por código)- No material:
spread180,initial_velocity_min3 einitial_velocity_max7,gravityemVector3(0, -6, 0),scale_curvecaindo para zero e umcolor_rampde branco para laranja para transparente.
No código, mova o node para o ponto do impacto e dispare:
extends Node3D
@onready var explosao: GPUParticles3D = $Explosao
func explodir_em(posicao: Vector3) -> void:
explosao.global_position = posicao
explosao.restart()
Como é one_shot, ele solta as 32 partículas de uma vez; elas abrem para todos os lados, incham, caem com a gravidade e somem em 0.7 segundo. Perfeito para a morte de um inimigo.
Receita 2: fumaça contínua
Fumaça é o oposto da explosão: fluxo lento, para cima, sem parar. Num GPUParticles3D com QuadMesh billboard e textura macia:
one_shot: desligadoamount: 24lifetime: 3.0- No material:
directionemVector3(0, 1, 0),spreadpequeno perto de 10,gravityemVector3(0, 0.6, 0)para empurrar para cima,initial_velocity_min0.3 einitial_velocity_max0.8,scale_curvecrescendo com o tempo ecolor_rampde cinza claro para transparente.
O lifetime longo e a velocidade baixa dão o movimento preguiçoso da fumaça. Ligue e desligue a fogueira por código:
extends Node3D
@onready var fumaca: GPUParticles3D = $Fumaca
func acender_fogueira() -> void:
fumaca.emitting = true
func apagar_fogueira() -> void:
fumaca.emitting = false
O mesmo esqueleto vira fogo: troque o gradiente para amarelo e vermelho, encurte o lifetime e inverta a escala para as chamas afinarem no topo. Fogo e fumaça costumam ser dois nodes empilhados na mesma posição. Para o fogo brilhar de verdade no ambiente, combine com uma luz; se quiser entender essa parte, veja como funciona a iluminação 3D no Godot para casar o efeito com o resto da cena.
Receita 3: poeira e faíscas de impacto
Faíscas são uma explosão pequena, rápida e brilhante, disparada quando algo bate em algo. É one_shot, amount entre 10 e 20, lifetime curto perto de 0.4, spread médio perto de 45 (as faíscas saltam mais na direção do golpe do que para todo lado), initial_velocity alta, gravidade puxando para baixo e um color_ramp branco para amarelo para transparente.
Dispare no ponto e, se quiser, oriente o leque de faíscas na direção da batida usando look_at:
extends Node3D
@onready var faiscas: GPUParticles3D = $Faiscas
func bater(ponto: Vector3, direcao: Vector3) -> void:
faiscas.global_position = ponto
# aponta o node na direcao do impacto, se direcao nao for zero
if direcao.length() > 0.01:
faiscas.look_at(ponto + direcao, Vector3.UP)
faiscas.restart()
Orientar o node faz o jato de faíscas apontar para onde o golpe veio, o que vende a sensação de impacto muito melhor do que faíscas saltando iguais para todos os lados. A poeira de pouso segue a mesma receita, só com spread bem aberto perto de 90, color_ramp em tons de marrom e velocidade menor, disparada quando o personagem toca o chão.
GPUParticles3D vs CPUParticles3D: dica de performance
A diferença está em quem faz a conta. O GPUParticles3D empurra o cálculo para a placa de vídeo, que processa milhares de partículas em paralelo, então o custo para a CPU do jogo fica baixíssimo. É a escolha padrão no 3D para desktop e a maioria dos celulares modernos.
O CPUParticles3D calcula tudo no processador. Aguenta menos partículas antes de pesar, mas roda em hardware antigo ou aparelhos que não lidam bem com os shaders de partícula. Regra prática: comece sempre com GPUParticles3D. Só troque para CPUParticles3D se testar num aparelho fraco e as partículas sumirem ou o FPS despencar. O Godot tem um atalho: com o GPUParticles3D selecionado, o menu do editor oferece "Convert to CPUParticles3D", que recria o efeito quase idêntico no outro node.
Alguns hábitos evitam quedas de FPS mesmo com GPU:
- Não exagere no
amount. Antes de subir a quantidade, teste se um número menor com textura melhor já convence. Muitas vezes 30 partículas bem feitas batem 300. - Use QuadMesh no draw pass. Mesh complexa multiplicada por centenas de partículas pesa. Quad com billboard resolve quase todo efeito de fumaça, fogo e faísca.
- Encurte o
lifetime. Partícula que vive mais tempo significa mais partículas vivas ao mesmo tempo. Impacto pode viver frações de segundo. - Reaproveite o material. Vários nodes de faísca iguais podem compartilhar o mesmo
ParticleProcessMaterial, o que economiza memória. - Desligue o que está fora de vista. Efeito contínuo longe da câmera ainda consome. Deixe
emitting = falsequando o node sai do campo de visão.
Do efeito ao jogo completo
Dominar partículas 3D transforma o feeling do seu jogo: cada golpe ganha faísca, cada morte ganha explosão, cada passo levanta poeira, cada tocha respira fumaça. Mas efeito bonito é só uma peça. Um projeto que sai do papel precisa de física, personagem, câmera, iluminação, som, telas e a cola que junta tudo, e aprender isso solto pela internet costuma virar um monte de peças que nunca se encaixam.
Se você ainda está montando a base do 3D, comece pelo passo a passo de criar seu primeiro jogo 3D no Godot e depois volte para plugar as partículas nos momentos certos. E se você quer ir do "consigo fazer uma explosão" para o "terminei e publiquei meu jogo", faz diferença seguir uma trilha ordenada. O curso da CursoGame.Dev pega você desde o básico do Godot e te leva até um jogo jogável, com as partículas no lugar certo e tudo o mais que um jogo de verdade precisa. Comece pelas receitas acima, quebre, conserte, e quando quiser a estrutura completa, o caminho está montado.
Perguntas frequentes
Qual a diferença entre GPUParticles3D e CPUParticles3D?
O GPUParticles3D calcula as partículas na placa de vídeo, aguenta milhares de partículas com custo baixo de CPU e é a escolha padrão no 3D. O CPUParticles3D calcula tudo no processador, roda em hardware antigo ou celulares que não lidam bem com os shaders de partícula e serve de plano B quando o efeito some ou trava no aparelho fraco.
Por que meu GPUParticles3D fica invisível na cena?
O erro mais comum é não atribuir um Draw Pass. Sem uma mesh no draw_pass_1 o node não tem o que desenhar e fica invisível mesmo emitindo. Cheque também se há um ParticleProcessMaterial no Process Material, se amount e lifetime são maiores que zero e se emitting está ligado.
Como disparo uma explosão de partículas 3D só uma vez por código?
Ative a propriedade one_shot no inspetor, deixe emitting desligado e no script chame particulas.restart() no momento do impacto. O restart() zera o estado interno, solta o lote de partículas uma única vez e para sozinho, que é o comportamento certo para explosão e faíscas.
Que mesh eu uso no Draw Pass das partículas 3D?
Para fumaça, fogo e faíscas o normal é um QuadMesh pequeno com um material que sempre encara a câmera (billboard) mais textura com transparência. QuadMesh é barato e billboard evita que a partícula plana apareça de lado. Meshes sólidas como esferas ou cubos servem para detritos e pedaços físicos.
Partículas 3D no Godot pesam muito no desempenho?
GPUParticles3D é barato mesmo com muitas partículas porque a GPU processa tudo em paralelo, mas amount alto, mesh complexa no draw pass, texturas grandes e lifetime longo somam custo. Use QuadMesh, reduza a quantidade, encurte o lifetime e reaproveite o mesmo material entre efeitos iguais.
Preciso escrever shader para colorir e escalar as partículas ao longo da vida?
Não. O ParticleProcessMaterial já traz color_ramp para o gradiente de cor e scale_curve (mais scale_min e scale_max) para o tamanho ao longo da vida. Você monta um Gradient e uma Curve no editor e as partículas mudam de cor e tamanho sem escrever nenhum shader.


