Voltar para o Blog
Quest Log

Efeito Dissolve no Shader Graph da Unity

Inimigo 3D estilizado se desfazendo em pedaços com borda laranja brilhante e faíscas no ar

Unity Shader Graph dissolve do zero: Simple Noise, Step e Alpha Clip, borda brilhante com Emission e um script C# que dissolve o inimigo quando ele morre.

Ferramenta:Unity

Efeito Dissolve no Shader Graph da Unity

O dissolve no Unity Shader Graph funciona assim: um ruído decide a ordem em que cada pixel some, uma propriedade de 0 a 1 avança esse limite, e o Alpha Clip descarta tudo que ficou abaixo. Acrescente uma faixa de cor emissiva logo antes do corte e o inimigo parece queimar até desaparecer.

Aqui você monta o graph nó a nó no URP do Unity 6.3 LTS, expõe o parâmetro de dissolve, escreve o script C# que dispara o efeito na morte do inimigo e adapta tudo para sprite 2D.

Como funciona o efeito dissolve

Pense numa folha de papel queimando. Cada ponto da folha tem um "tempo de queima" diferente. Quando o fogo passa daquele tempo, o ponto vira cinza e some, e logo antes de sumir ele brilha.

No shader, o ruído é esse tempo de queima: um valor entre 0 e 1 por pixel. A propriedade Dissolve é o relógio. A regra é uma comparação só:

  • Se ruído < Dissolve, o pixel é descartado.
  • Se ruído está entre Dissolve e Dissolve + largura da borda, o pixel brilha.
  • Caso contrário, o pixel aparece normal.

Com Dissolve = 0, nada some. Com Dissolve = 1, tudo some. O resto é animação.

Shader Graph: ruído e Alpha Clip Threshold

  1. No Project, botão direito > Create > Shader Graph > URP > Lit Shader Graph. Nomeie DissolveLit.
  2. Abra o graph. No Graph Inspector, aba Graph Settings, ligue Alpha Clipping. Isso libera a entrada Alpha Clip Threshold no bloco Fragment. Deixe Surface Type em Opaque: dissolve com clip não precisa de transparência e continua barato.
  3. Na Blackboard, crie as propriedades:
    • BaseMap (Texture2D), a textura do personagem.
    • BaseColor (Color), branco.
    • Dissolve (Float, modo Slider de 0 a 1). Em Reference, confira que ficou _Dissolve.
    • NoiseScale (Float), valor 30.
  4. Adicione um nó Simple Noise. Ligue NoiseScale em Scale. O preview mostra manchas cinzas variadas.
  5. Ligue a saída do Simple Noise em Alpha no Fragment.
  6. Ligue a propriedade Dissolve em Alpha Clip Threshold.
  7. Para a cor: Sample Texture 2D com BaseMap, multiplicado por BaseColor, ligado em Base Color.

Salve (Save Asset), crie um material a partir do graph e aplique num cubo. Mexa no slider Dissolve do material: o cubo deve se desfazer em manchas.

Por que funciona: o Alpha Clip descarta todo pixel cujo Alpha fica abaixo do Threshold. Como o Alpha recebe o ruído, o Threshold vira o "relógio" da queima.

Borda brilhante com Step e Emission

A borda é uma faixa logo acima do limite de corte. Para montá-la:

  1. Crie EdgeWidth (Float, 0,05) e EdgeColor (Color, modo HDR, laranja com intensidade em torno de 4).
  2. Nó Add: Dissolve + EdgeWidth.
  3. Nó Step: Edge recebe o ruído, In recebe o resultado do Add. O Step devolve 1 quando In é maior ou igual a Edge, ou seja, quando o ruído está abaixo de Dissolve + EdgeWidth. Como o que está abaixo de Dissolve já foi cortado, sobra exatamente a faixa da borda.
  4. Um segundo Step com Edge = 0,001 e In = Dissolve. Ele vale 0 quando Dissolve é zero, e evita que a borda apareça espalhada pelo objeto antes do efeito começar.
  5. Multiply os dois Steps, depois Multiply pelo EdgeColor.
  6. Ligue em Emission no Fragment.

Para o brilho estourar de verdade, ligue Post Processing na câmera e adicione um Volume com Bloom. Cor HDR acima de 1 mais Bloom é o que dá a sensação de brasa.

Quer uma borda com duas cores (amarelo por dentro, vermelho por fora)? Faça dois Steps com larguras diferentes, subtraia um do outro e pinte cada faixa com uma cor. É o mesmo raciocínio repetido.

Expondo o parâmetro de dissolve

Propriedade criada na Blackboard já aparece no material. O que importa para o script é a Reference (_Dissolve), não o nome de exibição. Mantenha Exposed marcado e confira a Reference no Node Settings da propriedade.

Se você trocar a Reference depois de escrever o script, o script para de funcionar sem erro nenhum: SetFloat com nome que não existe simplesmente não faz nada. Fixe a Reference cedo.

Animando por script na morte do inimigo

O script abaixo fica no inimigo. Quando Die() é chamado, ele desliga o collider, anima o _Dissolve de 0 a 1 e destrói o objeto no fim.

Arquivo EnemyDissolve.cs:

using System.Collections;
using UnityEngine;

public class EnemyDissolve : MonoBehaviour
{
    private static readonly int DissolveId = Shader.PropertyToID("_Dissolve");

    [SerializeField] private Renderer[] renderers;
    [SerializeField] private Collider enemyCollider;
    [SerializeField] private float duration = 1.2f;
    [SerializeField] private AnimationCurve dissolveCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

    private Material[] materials;
    private bool isDying;

    private void Awake()
    {
        if (renderers == null || renderers.Length == 0)
        {
            renderers = GetComponentsInChildren<Renderer>();
        }

        materials = new Material[renderers.Length];
        for (int i = 0; i < renderers.Length; i++)
        {
            materials[i] = renderers[i].material;
            materials[i].SetFloat(DissolveId, 0f);
        }
    }

    public void Die()
    {
        if (isDying)
        {
            return;
        }
        isDying = true;

        if (enemyCollider != null)
        {
            enemyCollider.enabled = false;
        }

        StartCoroutine(DissolveRoutine());
    }

    private IEnumerator DissolveRoutine()
    {
        float elapsed = 0f;

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float t = Mathf.Clamp01(elapsed / duration);
            SetDissolve(dissolveCurve.Evaluate(t));
            yield return null;
        }

        SetDissolve(1f);
        Destroy(gameObject);
    }

    private void SetDissolve(float value)
    {
        for (int i = 0; i < materials.Length; i++)
        {
            materials[i].SetFloat(DissolveId, value);
        }
    }
}

Decisões que importam aqui:

  • Shader.PropertyToID roda uma vez, num campo static readonly. Passar o int para SetFloat evita converter a string a cada frame.
  • renderer.material cria uma cópia do material para aquele inimigo. Sem isso, você mexeria no material compartilhado e todos os inimigos dissolveriam juntos.
  • O AnimationCurve deixa você ajustar o ritmo no Inspector: começar lento e acelerar costuma ficar melhor que linear.
  • O collider desliga antes da animação, para o jogador não acertar um inimigo que já morreu.

Chame GetComponent<EnemyDissolve>().Die() do seu script de vida quando o HP chegar a zero. Some umas faíscas de partícula e um som, e a morte do inimigo passa a dar recompensa visual. O post sobre game feel e juice mostra por que esse tipo de detalhe muda a sensação do jogo inteiro.

Shader isolado é a parte fácil. O difícil é quando o dissolve precisa conversar com vida, animação de morte, partícula, som, pool de inimigos e o resto da fase sem quebrar nada. Montar esse sistema todo junto, em jogo de verdade, é o que o curso de Unity faz com você do começo ao fim.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Dissolve em sprite 2D

Em sprite o raciocínio é o mesmo, mas o corte vem do alpha do próprio sprite:

  1. Create > Shader Graph > URP > Sprite Unlit Shader Graph (ou Sprite Lit, se a cena usa luz 2D).
  2. Sample Texture 2D com a textura principal. Em Sprite Shader Graph, crie a propriedade de textura com Reference _MainTex para receber o sprite do Sprite Renderer automaticamente.
  3. Adicione um Step com Edge = Dissolve e In = ruído. Ele devolve 1 onde o ruído é maior ou igual ao Dissolve, ou seja, onde o pixel fica, e 0 onde ele já queimou. É a mesma regra do Alpha Clip, escrita como máscara.
  4. Multiply o alpha do sprite (canal A) por esse resultado e ligue em Alpha.
  5. Para a borda, monte a faixa como no 3D e Add na cor (RGB) antes de ligar em Base Color.

Em pixel art, use o nó Posterize ou amostre o ruído numa resolução baixa (multiplique o UV, aplique Floor e divida de volta) para o dissolve respeitar a grade de pixels. Dissolve com ruído liso num sprite de 32x32 parece outro estilo de arte.

O script de cima funciona com SpriteRenderer sem mudança, porque SpriteRenderer também é um Renderer. Só troque o Collider por Collider2D.

Erros comuns: tudo some de uma vez e borda serrilhada

Tudo some de uma vez. O ruído não está ligado no Alpha, a escala está tão baixa que vira uma mancha só, ou o valor inicial do Dissolve já está alto. Teste o slider no material antes de mexer no script.

Nada acontece. Alpha Clipping desligado no Graph Settings, ou a Reference da propriedade não é _Dissolve. Confira os dois.

Borda aparece no objeto inteiro antes do efeito. Falta o segundo Step que zera a borda quando Dissolve é 0.

Borda serrilhada. Alpha Clip é um corte duro por natureza. Suavize a cor da borda com Smoothstep em vez de Step, aumente a largura e deixe o Bloom espalhar o brilho. Antialiasing na câmera (FXAA ou SMAA no URP) ajuda nas bordas de corte.

Todos os inimigos dissolvem juntos. O script está alterando sharedMaterial. Use material (ou um Material Property Block, se você conhece o trade-off com o SRP Batcher).

Material rosa. O graph está com Active Target errado ou o projeto não está em URP. Abra o Graph Settings e confira o target Universal.

Próximo passo

Faça uma variação: em vez de ruído, use um gradiente vertical (o nó UV, canal G) para o inimigo se desfazer de baixo para cima, depois misture gradiente com ruído para a linha de corte ficar irregular. Esse exercício ensina a pensar em máscara, que é a base de quase todo efeito de shader.

Se você também usa Godot, o post sobre shader de dissolve na Godot faz o mesmo efeito em código de shader, e comparar os dois ajuda a entender o que cada nó do Shader Graph está fazendo por baixo. Para os fundamentos de nós, propriedades e targets, leia o guia de Shader Graph na Unity.

Perguntas frequentes

Como fazer um shader de dissolve na Unity?

Crie um Lit Shader Graph no URP, ligue Alpha Clipping no Graph Settings, ligue um ruído (Simple Noise ou uma textura) na entrada Alpha e uma propriedade float na Alpha Clip Threshold. Quando a propriedade sobe de 0 a 1, os pixels com ruído abaixo dela são descartados e o objeto se desfaz.

Por que meu dissolve faz o objeto sumir de uma vez?

Normalmente o ruído está com escala baixa demais, a propriedade está fora da faixa 0 a 1 do ruído, ou o ruído não está ligado no Alpha. Confira no preview do nó Simple Noise se aparece uma mancha variada e teste a propriedade com o slider do material antes de animar por script.

Dá para usar o mesmo dissolve em sprite 2D?

Dá. Use um Sprite Unlit ou Sprite Lit Shader Graph, multiplique o alpha do sprite pelo resultado do Step e some a borda na cor. Como o sprite já é transparente, alpha 0 some do mesmo jeito que o Alpha Clip faz no 3D.

É melhor Simple Noise ou textura de ruído?

Simple Noise é ótimo para prototipar porque não precisa de arquivo. Em produção, uma textura de ruído em tons de cinza costuma ser mais barata e dá controle artístico: você pode pintar o padrão de queima que quiser.