0 votes

In 2D Godot shaders, I would like to create a drop shadow that only shows up inside a sprite. For example, if I had a donut like shape, I would like the shadow to only appear in the hole.

in Engine by (113 points)
edited by

1 Answer

+1 vote
Best answer

Here's the answer I came up with, for anyone else struggling with this. The following shader can be applied to any binary image consisting of white and transparent, where the white area is where you want the shadow to appear and the transparent area is outside:

shader_type canvas_item;

uniform float radius = 5.0;
uniform float x = 0.0;
uniform float y = 0.0;

void fragment(){
    vec2 px = TEXTURE_PIXEL_SIZE;
    float total_alpha = 0.0;

    for(float h = (radius - 1.0) * -1.0; h < radius; h++){
        for(float v = (radius - 1.0) * -1.0; v < radius; v++){
            if(length(vec2(h, v)) > radius) continue;
            total_alpha += texture(TEXTURE, UV + px * vec2(h - x, v - y)).a;
    float alpha_ratio = total_alpha / (radius * radius * 4.0);
    COLOR.a = clamp(1.0 - alpha_ratio, 0.0, 1.0);

The idea here is for every pixel on the image, the more transparency there is within the specified radius of the given pixel, the darker that pixel should get. This should darken the regions near the edges of the binary image and the transparent area outside of the white area and lighten everything else. The x and y values will offset the shadow, and radius will make it blurrier or sharper. Simply modulate the binary image to get the shadow color that you want. Be sure to leave at least a 1 pixel margin around the edges of the binary image, so none of the white pixels touches the edges of the image (if white pixels touch the edges, this shader ignores that region and makes a shadowless area where there shouldn't be one).

Unfortunately, there currently isn't a way for the shader itself to get light position information in fragment(), so you'll need to use GDScript and vector math to position the shadow. Simply adjust the x and y values to move the shadow around.

by (113 points)
edited by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.