Godot 4+ 3D Vertical Dissolve Shader

A reusable vertical dissolve effect for MeshInstance3D with an animated noise edge, customizable edge color, and emission glow. This shader should work with Godot 4’s Forward+, Mobile, and Compatibility renderers

Setup

  1. Create a ShaderMaterial and assign the provided dissolve shader to it.
  2. Assign the ShaderMaterial to your MeshInstance3DMaterial Override.
  3. Assign a grayscale noise texture to the shader’s Noise Texture property.
    • Seamless/tileable noise works best.
    • Perlin, Simplex, Worley, or similar noise textures work well.
  4. Adjust the shader parameters in the ShaderMaterial inspector.

The dissolve is controlled by the shader’s offset:

  • 0.0 = fully visible
  • 1.0 = fully dissolved

Basic usage

You only need to change offset from your script.

Dissolve over 2 seconds

 
var mat = $MeshInstance3D.material_override as ShaderMaterial

for i in 60:
	mat.set_shader_parameter("offset", float(i) / 59.0)
	await get_tree().create_timer(2.0 / 60.0).timeout
 

Or with a Tween — recommended

 
var mat = $MeshInstance3D.material_override as ShaderMaterial

mat.set_shader_parameter("offset", 0.0)

create_tween().tween_method(
	func(value): mat.set_shader_parameter("offset", value),
	0.0,
	1.0,
	2.0
)
 

To make it reappear, simply reverse the values:

 
create_tween().tween_method(
	func(value): mat.set_shader_parameter("offset", value),
	1.0,
	0.0,
	2.0
)
 

Direction

Change the shader’s Up parameter:

 
Up = true   → Bottom → Top
Up = false  → Top → Bottom
 

 

That’s all you need — the rest can be configured directly in the ShaderMaterial inspector.

 

 

Shader code
// Core dissolve controls
// Variable				What it does [Typical value]
// Offset				How far the mesh has dissolved. [0 = fully visible, 1 = fully gone. 0.0 → 1.0]
// Up					Direction of the dissolve. [true = bottom → top, false = top → bottom. true]
// Border Color			Color of the glowing edge where the dissolve is happening. [Yellow]
// Border Height		Thickness of the colored transition edge. [Larger = thicker. 0.1]
// Wave Amplitude		How much the dissolve edge moves up/down in a wave pattern [0.05]
// Wave Frequency		How frequently the edge waves across the X axis. [Higher = more waves. 3.0]
// Wave Phase			Offsets the wave pattern horizontally. [0.1]
// Emission Intensity	Brightness of the border's glow. [Higher = brighter. 2.0]
// Noise Speed			How quickly the noise pattern moves over time. [0.1]
// Noise Influence		How strongly the noise distorts the dissolve edge. [0.05]

// Noise Influence determines how much the texture affects the dissolve edge.
// What should you put in Noise Texture? : A grayscale noise texture.
// Something like:
// Perlin noise
// Simplex noise
// Worley/cellular noise
// Cloud/noise texture
// Ideally a seamless/tileable texture.
// For example, a 256×256 grayscale noise image works perfectly well.

shader_type spatial;
render_mode cull_back;

uniform sampler2D albedo_texture : source_color;
uniform sampler2D noiseTexture : source_color;

uniform bool has_texture = false;
uniform vec4 base_color : source_color = vec4(1.0);

uniform float offset = 0.0;
uniform bool up = true;

uniform vec4 borderColor : source_color = vec4(1.0, 1.0, 0.0, 1.0);
uniform float borderHeight = 0.1;

uniform float waveAmplitude = 0.05;
uniform float waveFrequency = 3.0;
uniform float wavePhase = 0.1;

uniform float emissionIntensity = 2.0;
uniform float noiseSpeed = 0.1;
uniform float noiseInfluence = 0.05;

uniform vec2 noiseUVScale = vec2(1.0);
uniform vec2 textureUVScale = vec2(1.0);

varying vec3 local_pos;


void vertex() {
	local_pos = VERTEX;
}


void fragment() {

	// -----------------------------------------
	// Original material appearance
	// -----------------------------------------

	vec4 text = base_color;

	if (has_texture) {
		text *= texture(albedo_texture, UV * textureUVScale);
	}


	// -----------------------------------------
	// Animated noise
	// -----------------------------------------

	vec2 noise_uv = UV * noiseUVScale;
	noise_uv.y -= TIME * noiseSpeed;

	float noise = texture(noiseTexture, noise_uv).r;


	// -----------------------------------------
	// 1. Normalized vertical position
	// -----------------------------------------

	float height = (local_pos.y + 1.0) / 2.0;


	// -----------------------------------------
	// 2. Wavy dissolve edge
	// -----------------------------------------

	float wave = sin(
		local_pos.x * waveFrequency + wavePhase
	);

	wave += sin(
		local_pos.x * waveFrequency * 1.7 + wavePhase
	);

	wave *= waveAmplitude;


	float edge = height + wave;


	// Center noise around zero
	edge += (noise - 0.5) * noiseInfluence;


	// -----------------------------------------
	// 3. Convert to dissolve coordinate
	// -----------------------------------------

	float dissolve_position;

	if (up) {
		dissolve_position = edge;
	}
	else {
		dissolve_position = 1.0 - edge;
	}


	// -----------------------------------------
	// 4. Guarantee proper endpoints
	// -----------------------------------------

	if (offset <= 0.0) {
		dissolve_position = 1.0;
	}

	if (offset >= 1.0) {
		dissolve_position = -1.0;
	}


	// -----------------------------------------
	// 5. Distance from dissolve edge
	// -----------------------------------------

	float distance = dissolve_position - offset;


	// -----------------------------------------
	// 6. Discard dissolved area
	// -----------------------------------------

	if (distance < 0.0) {
		discard;
	}


	// -----------------------------------------
	// 7. Yellow dissolve border
	// -----------------------------------------

	float border = 1.0 - smoothstep(
		0.0,
		borderHeight,
		distance
	);


	// -----------------------------------------
	// 8. Final color
	// -----------------------------------------

	vec4 color = text;

	color.rgb = mix(
		color.rgb,
		borderColor.rgb,
		border
	);


	ALBEDO = color.rgb;
	ALPHA = color.a;


	// -----------------------------------------
	// 9. Border emission
	// -----------------------------------------

	EMISSION =
		borderColor.rgb *
		border *
		emissionIntensity;
}
Live Preview
Tags
3d, 3D dissolve vfx, Dissolve Effect, dissolve shader, Mesh Dissolve, vertical Dissolve
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

guest

0 Comments
Oldest
Newest Most Voted