๐ฅ Lesson 8.4: Building a Dissolve Shader (Mini-Project)
Time to ship an effect. A dissolve shader eats an object away pixel by pixel, leaving a glowing burning edge โ the classic "enemy disintegrates on death" look. You'll build the whole graph (noise, a threshold, alpha clipping, an emissive rim) and then drive it from a tiny script so any object can dissolve on command. This is Module 8's capstone: lighting, shaders, and code all in one demo.
๐ฏ Learning Objectives
By the end of this lesson, you will be able to:
- Use a Simple Noise node as the pattern that decides what dissolves first
- Turn noise + a Dissolve float property into a hard cutoff with a Step node
- Drive Alpha Clip Threshold to actually remove pixels
- Build a glowing emissive edge from the same threshold
- Enable Alpha Clipping in the graph's settings so clipping works
- Write a C# script that animates the Dissolve property so an object disintegrates over time
Estimated Time: 50 minutes ยท Prerequisite: Lesson 8.3 (Intro to Shader Graph)
In This Lesson
How a Dissolve Works
The trick is disarmingly simple. Every pixel gets a random-ish value from a noise texture (0 to 1). You then pick a threshold: any pixel whose noise value is below the threshold gets erased. Slide the threshold from 0 to 1 over time and the object vanishes in a natural, blotchy pattern instead of a clean wipe.
Two ingredients turn that into a convincing effect:
- Alpha clipping โ the shader discards (doesn't draw) any pixel below the threshold, punching real holes in the mesh.
- An emissive edge โ the thin band of pixels right at the threshold glows hot, so it looks like the object is burning away rather than turning invisible.
๐ Definition
Alpha clipping (alpha test): a shader feature that fully discards any pixel whose alpha falls below a cutoff โ no partial transparency, just there or gone. It's what lets a dissolve create hard, crisp holes and is far cheaper than true transparency.
Graph Setup & Alpha Clipping
Create a URP โธ Lit Shader Graph called SG_Dissolve. Before wiring anything, turn on alpha clipping or the effect can't remove pixels:
- Open the Graph Inspector (top-right of the editor) โธ Graph Settings.
- Tick Alpha Clipping. This adds an Alpha Clip Threshold input to the Fragment block of the Master Stack.
Then add these Blackboard properties:
BaseTex(Texture2D) โ the object's normal surface texture.Dissolve(Float, range 0โ1, default 0) โ how far along the dissolve is. This is the value your script animates.NoiseScale(Float, default 12) โ how fine or chunky the dissolve pattern is.EdgeWidth(Float, default 0.05) โ how thick the glowing edge band is.EdgeColor(Color, HDR) โ the glow colour; make it HDR so it can be brighter than white and bloom later.
โ ๏ธ No Alpha Clipping = nothing disappears
If you skip the Graph Settings step, wiring a value into Alpha Clip Threshold does nothing because the input isn't even there. If your object refuses to dissolve, this checkbox is the first thing to check.
The Dissolve Network
Here is the heart of the mini-project โ the dissolve network rebuilt exactly as you'll wire it in Shader Graph:
Dissolve to drive Alpha Clip Threshold (erasing pixels), the other carves a thin band via EdgeWidth, multiplies it by the HDR EdgeColor, and drives Emission (the glow). The object's BaseTex feeds Base Color.Reading it left to right:
- Simple Noise (scaled by
NoiseScale) gives each pixel a value 0โ1. - A Step node compares that noise against
Dissolve. Step outputs 1 where noise โฅ Dissolve and 0 below it โ a hard cutoff. Feed the result (inverted as needed) into Alpha Clip Threshold so low pixels get discarded. - As
Dissolverises toward 1, more pixels fall below the cutoff and disappear.
โ Pro Tip
If the dissolve goes the "wrong way" (object appears instead of vanishes), you've got the comparison backwards. Either swap the Step's Edge/In inputs or subtract from 1 with a One Minus node. Shaders are full of these little sign flips โ flip and re-check rather than agonising.
The Glowing Edge
A dissolve without a burning edge looks like a bug, not an effect. The edge is just a second threshold offset slightly from the first, so it isolates the thin band of pixels that are about to disappear:
- Take the same noise, and build a band: pixels where noise is between
DissolveandDissolve + EdgeWidth. A second Step (or a Smoothstep for a softer band) isolates them. - Multiply that band by the HDR
EdgeColorso only the band glows. - Feed the result into Emission. Because the colour is HDR (values above 1), it'll bloom brightly once you add post-processing in the next module.
Now the leading edge of the dissolve burns hot orange while everything behind it is already gone. That single extra branch is the difference between "cheap" and "cool."
๐ก HDR + Bloom = fire. An emissive edge with an HDR colour looks merely bright on its own. Add a URP Bloom post-process (Lesson 9.3) and that same edge blooms into a glowing, fiery rim. Author the glow now; it pays off later.
Animating It from Code
The shader can dissolve to any fixed amount, but the effect is the animation. Give Dissolve the Reference name _Dissolve in the Graph Inspector, then drive it from a script. Note we use a MaterialPropertyBlock so we don't create a leaked material instance per object:
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class DissolveController : MonoBehaviour
{
[SerializeField] float duration = 1.5f; // seconds to fully dissolve
[SerializeField] bool destroyWhenDone = true;
static readonly int DissolveID = Shader.PropertyToID("_Dissolve");
Renderer rend;
MaterialPropertyBlock mpb;
void Awake()
{
rend = GetComponent<Renderer>();
mpb = new MaterialPropertyBlock();
}
// Call this from anywhere โ e.g. when an enemy dies
public void Dissolve()
{
StopAllCoroutines();
StartCoroutine(DissolveRoutine());
}
IEnumerator DissolveRoutine()
{
float t = 0f;
while (t < duration)
{
t += Time.deltaTime;
float amount = Mathf.Clamp01(t / duration); // 0 -> 1
rend.GetPropertyBlock(mpb);
mpb.SetFloat(DissolveID, amount);
rend.SetPropertyBlock(mpb);
yield return null;
}
if (destroyWhenDone)
Destroy(gameObject);
}
}
Attach this to any object using the dissolve material, and call Dissolve() from your death logic. Over duration seconds it ramps _Dissolve from 0 to 1 and the object burns away, then removes itself.
โ ๏ธ Use a hashed ID and a property block
Shader.PropertyToID("_Dissolve") converts the name to an int once โ faster and typo-safe versus passing the string every frame. And touching rend.material directly clones the material (a hidden allocation you must clean up); a MaterialPropertyBlock changes this renderer's value with no clone, so a hundred dissolving enemies don't spawn a hundred stray materials.
Mini-Project: Disintegrate on Death
Tie the module together. Reuse the health/damage interface from Module 7: when an enemy's health hits zero, instead of a plain Destroy, trigger the dissolve.
using UnityEngine;
// Assumes an IDamageable / health system from Module 7 raises OnDied.
[RequireComponent(typeof(DissolveController))]
public class EnemyDeathDissolve : MonoBehaviour
{
DissolveController dissolver;
void Awake() => dissolver = GetComponent<DissolveController>();
// Hook this to your health component's death event
public void OnDied()
{
// stop AI, disable colliders, etc. here if needed
dissolver.Dissolve(); // burns away, then self-destructs
}
}
Wire OnDied to the health event (a UnityEvent in the Inspector, or a C# event from Module 2). Now shooting an enemy to zero HP makes it disintegrate with a glowing edge instead of popping out of existence โ a small change that makes combat feel dramatically more polished.
โ Pro Tip
Make the EdgeColor match the enemy type โ icy blue for a frost enemy, sickly green for a toxic one โ all from the same shader graph, just different materials. That's the payoff of exposing properties on the Blackboard back in Lesson 8.3.
Hands-on Challenge
๐๏ธ Exercise 1: Build and drive the dissolve
Objective: a cube that fully disintegrates on a key press.
- Create
SG_Dissolvewith Alpha Clipping on and the five properties from the setup section. - Wire the network in Figure 1: Simple Noise โ Step (vs
Dissolve) โ Alpha Clip Threshold, and the edge band โ Multiply byEdgeColorโ Emission. - Make a material, assign it to a cube, and drag the
Dissolveslider in the material Inspector from 0 to 1 โ confirm the cube burns away with a glowing edge. - Add
DissolveController, and a tiny script that callsDissolve()when you press a key (use the new Input System from Module 3).
๐ก Hint: dragging the slider does nothing
Check three things: Alpha Clipping is ticked in Graph Settings (so the Alpha Clip Threshold input exists), your Step output is actually wired into it, and the Dissolve property's Reference is _Dissolve so the script matches. If it dissolves inverted, add a One Minus node.
โ Success check
Pressing the key makes the cube disintegrate over ~1.5s with a hot glowing edge leading the way, and the GameObject is gone afterwards โ with no stray cloned materials in the scene.
๐๏ธ Exercise 2: Reverse it โ a materialize-in
Animate _Dissolve from 1 back to 0 instead, and skip the Destroy. Now the object assembles out of nothing โ perfect for a spawn or teleport-in effect. Same graph, opposite direction: proof that one shader can serve two effects.
๐ฏ Quick Quiz
Question 1: Which node gives each pixel the semi-random value that decides what dissolves first?
Question 2: You wired the dissolve up but nothing ever disappears. What's the most likely cause?
Question 3: Why does the script use a MaterialPropertyBlock instead of setting rend.material.SetFloat(...)?
Summary
๐ Key Takeaways
- A dissolve = noise + a rising threshold: pixels below the cutoff are discarded via Alpha Clip Threshold.
- You must enable Alpha Clipping in Graph Settings for the threshold input to exist.
- A Step node turns the smooth noise into a hard on/off cutoff; a second Step (or Smoothstep) carves the glowing edge band.
- Multiply the edge band by an HDR EdgeColor into Emission for a burning rim that blooms later.
- Animate the
_Dissolvefloat from C# โ with a hashed ID and a MaterialPropertyBlock โ to disintegrate an object over time. - One graph, many effects: reverse the value for a materialize-in; retint EdgeColor per enemy.
๐ What's Next?
Module 8 is done โ you can light a scene, bake it, and author your own shaders. Module 9 turns up the spectacle. In Lesson 9.1: Particle Systems (Shuriken) you'll add smoke, sparks, and fire with Unity's classic particle system โ the perfect companion to the dissolve you just built.
๐ฅ You shipped a real shader effect
Noise, a threshold, a glowing edge, and a coroutine that drives it โ that's a complete, reusable dissolve. The same three ideas underlie force-fields, teleports, and burn-away transitions across the whole industry.