Dynamic Drop Shadow (CanvasItem, NO ColorRect needed!)

Needs only one material and no extra nodes! A drag-and-drop drop shadow effect for CanvasItems with controls for direction, color (including opacity), and distance. Rotates automatically when the CanvasItem is rotated.

The video is a little outdated because I added a parameter for color like twenty minutes afterwards.

CanvasItem shaders don’t support next pass, and since I didn’t want to use extra nodes for the effect, it necessitated some weird fragment shader stuff where I stretch the mesh and shrink the UV to give space for the shadow.

Shader code
shader_type canvas_item;

uniform int dist = 2;
uniform vec4 color: source_color = vec4(0.0, 0.0, 0.0, 0.5);
uniform float angle: hint_range(0.0, 360.0) = 90.0;

varying vec2 main_uv;
varying vec2 shadow_uv;

void vertex() {
	
	vec2 uv = TEXTURE_PIXEL_SIZE * float(dist * 2);
	
	vec2 uv_half = uv * 0.5;
	vec2 uv_dist = uv + 1.0;
	
	vec2 shadow_direction = (vec4(cos(radians(angle)), sin(radians(angle)), 0.0, 1.0) * MODEL_MATRIX).xy;
	
	VERTEX *= uv_dist;
	
	main_uv = UV * uv_dist - uv_half;
	shadow_uv = main_uv - shadow_direction * uv_half;
}

void fragment() {
	
	// sample colors for shadow
	float shadow_amt = texture(TEXTURE, shadow_uv).a
		* step(-1.0, -shadow_uv.x)
		* step(-1.0, -shadow_uv.y)
		* step(0.0, shadow_uv.x)
		* step(0.0, shadow_uv.y);
	
	// shadow color
	COLOR = color * shadow_amt;
	
	// sample main colors on top of shadow
	vec4 main_color = texture(TEXTURE, main_uv)
		* step(-1.0, -main_uv.x)
		* step(-1.0, -main_uv.y)
		* step(0.0, main_uv.x)
		* step(0.0, main_uv.y);
	
	// need to make area where main and shadow overlap black for next step
	COLOR = mix(COLOR, vec4(0.0, 0.0, 0.0, 1.0), main_color.a);

	// add main color on top of blackened area
	COLOR += main_color * main_color.a;
}
Live Preview
Tags
2d, pixel, pixelart, shadow, sprite
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from dairycultist

Related shaders

guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
tazzan
tazzan
1 month ago

I’m really loving this shader, but I’m getting an issue where the shader breaks nine-sliced buttons. I think it’s something to do with the UV calculation being based off of the texture instead of the rendered sprite, but I’m not knowledgeable enough in GD Shaders to fix it myself.

Here’s what it looks like with and without the shader:
comment image
comment image

Last edited 1 month ago by tazzan