Examples of disintegration effects with godot 2d particle shaders
The following process can be followed to create a similar effect starting from any particles material. The full source code for this example can be found in undertale.tres.
- Set up a Particle2D node with the desired parameters and convert the ParticlesMaterial to a ShaderMaterial
- Set explosiveness to 1 and the particle amount to the number of pixels in the image
- Add a uniform to pass in the image that will be disintegrated
uniform sampler2D sprite;
- In the vertex function calculate a starting position for each particle from its
base_number
ivec2 sprite_size = textureSize(sprite, 0);
int x = int(base_number) % sprite_size.x;
int y = (int(base_number) / sprite_size.x) % sprite_size.y;
ivec2 starting_position = ivec2(x, y);
- In the restart block set the particles position, kept in
TRANSFORM[3]
to the starting position
TRANSFORM[3].xy = vec2(starting_position);
- Remove the
color_value
uniform and replace it with a variable that gets the color from the particles starting position in the image, deactivate the particle if it is fully transparent
vec4 color_value = texelFetch(sprite, starting_position, 0);
if (color_value.a == 0.0) { ACTIVE = false; }
- Add a uniform to control the fraction of the lifetime a particle will be displayed, this is needed to compensate for the time the effect takes to complete
uniform float particle_lifetime_fraction : hint_range(0.0, 1.0, 0.01);
- The variable
tv
holds the fraction of particle lifetime elapsed, adjust it byparticle_lifetime_fraction
tv = clamp(CUSTOM.y / CUSTOM.w / particle_lifetime_fraction, 0.0, 1.0);
- Add a uniform to control the fraction of the sprite disintegrated
uniform float progress : hint_range(0.0, 1.0, 0.01);
- The else block should only run on particles that have disintegrated, ie. particles in the top fraction of the image, replace the else with an else if
} else if (float(starting_position.y) / float(sprite_size.y) < progress) {
- The particle position is by default automatically calculated using the value in
VELOCITY
, to calculate it manually add thedisable_velocity
render mode
render_mode disable_velocity;
- In the above else if block manualy calculate the new position
TRANSFORM[3].xyz += VELOCITY * DELTA;
- Add a script to the Particle2D to tween the progress uniform. The tween should take
lifetime * (1 - particle_lifetime_fraction)
to complete so that the last particles will fully fade inlifetime
seconds
func start():
restart()
emitting = true
var frac = process_material.get("shader_param/particle_lifetime_fraction")
process_material.set("shader_param/progress", 0.0)
var tween = get_tree().create_tween()
tween.tween_property(process_material,
"shader_param/progress",
1.0,
lifetime * (1.0 - frac))
- (Optional) The resulting shader potentially contains many lines using unused uniforms which can be removed to improve performance. The cleaned up shader can be found in undertale_cleaned.tres