The shader for dissolving a 2D sprite isn’t all that different from dissolving a 3D object. However, canvas items don’t have separate EMISSION
, ALBEDO
or ALPHA
outputs, so you’ll need to compose the final color yourself.
You can use the Modulate property of sprites to change base color, and the texture is inside the Sprite already. That means you don’t need the albedo
or albedo_texture
uniforms. Everything else stays.
shader_type canvas_item; uniform sampler2D dissolve_texture; uniform vec4 burn_color : hint_color = vec4(1); uniform float burn_size : hint_range(0, 2); uniform float dissolve_amount : hint_range(0, 1); uniform float emission_amount;
You start by grabbing the color of the regular sprite texture.
void fragment() { vec4 out_color = texture(TEXTURE, UV); }
Everything from the dissolve mask up to the emission value is the same, except you should store the final emission color in a local variable because you’ll mix it into the output color at the end.
float sample = texture(dissolve_texture, UV).r; float emission_value = 1.0 - smoothstep(dissolve_amount, dissolve_amount + burn_size, sample); vec3 emission = burn_color.rgb * emission_value * emission_amount;
What was ALPHA
in 3D is put into the COLOR
’s alpha value instead. Because graphics cards see sprites as rectangles with textures on them, you need to mix that alpha to the regular sprite’s alpha color. We do that by multiplying it with the texture’s alpha. That way, edges that are transparent in the original sprites are still transparent in the burn.
COLOR.a = smoothstep(dissolve_amount - burn_size, dissolve_amount, sample) * out_color.a;
The RGB of the color is the largest amount between the regular sprite’s color and the emission color.
COLOR.rgb = max(out_color.rgb, emission);
Bring it all together to get the final code:
shader_type canvas_item; uniform sampler2D dissolve_texture; uniform vec4 burn_color : hint_color = vec4(1); uniform float burn_size : hint_range(0, 2); uniform float dissolve_amount : hint_range(0, 1); uniform float emission_amount; void fragment() { vec4 out_color = texture(TEXTURE, UV); float sample = texture(dissolve_texture, UV).r; float emission_value = 1.0 - smoothstep(dissolve_amount, dissolve_amount + burn_size, sample); vec3 emission = burn_color.rgb * emission_value * emission_amount; COLOR = vec4(max(out_color.rgb, emission), smoothstep(dissolve_amount - burn_size, dissolve_amount, sample) * out_color.a); }
Change the Dissolve Amount property on the shader to burn it, or use set_shader_param("dissolve_amount", x)
to control it from code. It works great with Tween’s interpolate_method
function, or with an AnimationPlayer.
Making a 2D object glow is the same as for a 3D one. Add a new WorldEnvironment node and assign it a new environment. However, if you turn on Glow and set Blend Mode to Additive, nothing happens!
That’s because 2D scenes are a little different. In a 3D scene, the world environment is like a quad attached to the camera; it has all the information of the 3D world at its disposal.
In a 2D scene, there’s no 3D information; the world is a flat square sitting on the ground and there are no objects or even any color. We have to give it something to post-process.
For the graphic artists among you: if you ever tried to merge a glowing Color Dodge layer onto a transparent Normal layer in Photoshop, you might be familiar with this exact situation.
To fix this, look for the Background dropdown and set the Mode property to Canvas. Now our post-process WorldEnvironment’s world is still a flat square, but it also has color data which our WorldEnvironment can use.
All the other settings that applied in a WorldEnvironment node for 3D apply here as well.