2D shadows shader

Features:

  • Any X/Y offset
  • Any color
  • debug helper
  • no need to prepare an image

Github: https://github.com/TABmk/godot-2d-shadow-shader

YouTube preview: https://www.youtube.com/watch?v=PBE6ZlaGigI

Shader code
// version: 1.1
// repository: https://github.com/TABmk/godot-2d-shadow-shader

shader_type canvas_item;

uniform float borderScale = 2.0;
uniform vec2 offset = vec2(-10.0, -10.0);
uniform vec4 color : source_color;
uniform vec4 modulate : source_color = vec4(1.0);
// turn this on to see where the shadow will be clipped
uniform bool debug = false;

// fragment() function works properly only within the area of an element.
// We can scale this area by scaling the entire element within vertex(), and then scaling it down in fragment().

// fragment works properly only iside element's area. But we can scale this area
// by scaling whole element inside vertex() and then downscale it in fragment()

// scaling element
void vertex() {
	VERTEX.xy *= vec2(borderScale);
}

// fragment downscaling "trail" fix
// while downscaling an element in fragment(), it makes a "trail" of the last pixel in X and Y
vec4 hideExtra(vec2 uv, sampler2D txtr, bool isMain) {
	if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0) {
		vec4 texColor = texture(txtr, uv);
		return isMain ? texColor : vec4(color.rgb, texColor.a - (1.0 - color.a));
	}
	return vec4(0.0);
}

void fragment() {
	// size of a single pixel
	vec2 singlePX = TEXTURE_PIXEL_SIZE;

	// main downscaled and centered element
	vec2 uv = UV * borderScale - (0.5 * (borderScale - 1.0));
	vec4 uv_texture = hideExtra(uv, TEXTURE, true);

	// apply custom modulate to main sprite
	uv_texture *= modulate;

	// same element, but with offset
	vec2 shadow_uv = uv + offset * singlePX;
	vec4 shadow = hideExtra(shadow_uv, TEXTURE, false);

	// show main element on top of shadow
	vec4 res = mix(shadow, uv_texture, uv_texture.a);
	// debug layer. Turn on if you need a big offset
	vec4 debug_layer = vec4(1.0, 0.0, 0.0, 0.3);
	COLOR = mix(debug ? debug_layer : res, res, res.a);
}
Tags
2d, shadow
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

2D Top-Down Shadows (Tilemap Ready)

Dynamic 2D Lights and Soft Shadows

Drop-in PBR 2d lighting system with soft shadows and ambient occlusion

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
zdrmlp
zdrmlp
2 months ago

is there a way to also make the shadow looks soft on the edge or have fade near edges? so it looks smooth?