video

Dissolve shader: VFX's bread and butter

If there is one shader trick anyone should learn about when creating visual effects, it's dissolving, as it is very versatile and allows you to do many effects with just 1 shader.

All the files are available on GitHub, you can check out the project and read along to get the gist. All the files related to this article are in the "dissolve" folder.

Dissolve 101

Binary Mask

Let's create an empty scene with a ColorRect node and a ShaderMaterial resource as its material and edit our first iteration of the shader.

For that we only need:

  • A mask texture (sampler2D uniform)
  • A dissolve value (float uniform) ranged between 0 and 1 to shift the edge of the mask
shader_type canvas_item;

uniform sampler2D noise_sampler : repeat_enable;
uniform float dissolve : hint_range(0.0, 1.0, 0.1) = 0.0;

void fragment() {
	float mask = texture(noise_sampler, UV).x;
    // set COLOR.a of ALPHA with dissolve "method"
}

This code above is the base setup for the dissolve effect, the important part is the dissolve "method" you use to apply your mask. This one is the simpler mask effect we can do, as we simply pick a mask texture and map its value to 0.0 or 1.0 producing a hard edge between the visible and masked area.

To do that, we could use the step function and give it dissolve as its edge argument and mask as its value argument.

COLOR.a = step(dissolve, mask);

Rounding the value with a ceil, round or floor function is also valid, but this one requires to offset the mask value with the dissolve value.

COLOR.a = ceil(mask - dissolve);

Smooth Mask

Binary mask is great for some art styles, but sometimes you also need to be able to control the smoothness of your mask. Let's use the previous setup and add a smoothnes parameter.

uniform float smoothness : hint_range(0.0, 1.0, 0.01) = 0.1;

The masked method is a bit different, as we need to remap the dissolve value to cover the min and max edge of smoothness. For that I'm using the map method as a quick solution. Feeding all this into the smootstep method produces a mask with configurable smooth edges.

shader_type canvas_item;

uniform sampler2D noise_sampler : repeat_enable;
uniform float dissolve : hint_range(0.0, 1.0, 0.1) = 0.0;
uniform float smoothness : hint_range(0.0, 1.0, 0.01) = 0.1;

// Map Method

void fragment() {
	float mask = texture(noise_sampler, UV).x;
	float mapped_dissolve = map(dissolve, 0.0, 1.0, - smoothness, 1.0 + smoothness);
	COLOR.a *= smoothstep( - smoothness, + smoothness, mask - mapped_dissolve);
}

We now have 2 solutions for dissolving stuff, but you don't have to stop here, the possibility are endless as you can throw other property in the mix.

  • Dissolving along UV coordinate
  • Mixing Albedo and Emission to create a burning paper effect
  • etc...
video

Spicing up particles

The practical application of this method is wide, I wouldn't be able to list everything in one blog post. Think of it as an extra tool in your VFX toolbox. However, there is one use case that I would like to highlight, which is mixing this method with particles to create a utility shader that you can throw in your particle system to create and iterate quick effects.

This section focuses on `particles_dissolve.gdshader`, explaining this shader would be partly redundant with what has been described above. So I'll only highlight the important points.

Differences

This example shader is similar to the smooth mask we did previously but diverges in some parts.

  • It doesn't map the mask from 1.0 to 0.0, as it would display a fully rendered quad when a particle spawns.
  • It doesn't have a dissolve parameter but uses the particle system INSTANCE_CUSTOM.y (representing the particle lifetime value as we want the particle to dissolve along its lifetime.)
float noise = clamp(texture(noise_sampler, UV * noise_scale + custom.z).x - custom.y, 0.0, 1.0);

Additions

There are also a few more parameters added

  • edge: represents the side of the mask favored during dissolving.
  • energy: particle emission power, 1.0 is neutral.
  • gradient_sampler: color along the mask, accounting for dissolving.
video
video

This shader can create simple effects such as smoke or dust. It is possible to create more “complex” effects, such as the fire above constructed with several particle systems. I would recommend using this technique in combination with other elements for greater variety. Dissolve shader is good for creating or garnishing organic effects like magic spells.

Going further

This blog post only scratches the surface of this topic and provides a few simple basics to take you further. If you found it interesting or inspiring, don't hesitate to share what you have done with it. If you have any feedback or comments, tell me :)!