Help with Blurred Shadow

Godot Version

4.3

Question

Hello! I can’t get the shadows from the houses to be blurred, I’ve tried everything. Tell me, which way should I look to find a solution?

Снимок экрана 2024-12-21 в 20.22.42

shader_type canvas_item;

uniform float shadow_opacity : hint_range(0.0, 1.0) = 0.5; // Shadow opacity
uniform vec2 shadow_offset = vec2(0.1, -0.1); // Shadow offset
uniform float blur_radius : hint_range(0.0, 10.0) = 5.0; // Blur radius

void fragment() {
    // Get the base texture color
    vec4 base_color = texture(TEXTURE, UV);

    // If this is part of the building, render it
    if (base_color.a > 0.0) {
        COLOR = base_color; // Render the building
    } else {
        // Offset UV to get the shadow position
        vec2 shadow_uv = UV + shadow_offset;

        // Final shadow color and total weight
        vec4 shadow_color = vec4(0.0);
        float total_weight = 0.0;

        // Iterate over pixels around the shadow position
        for (int x = -int(blur_radius); x <= int(blur_radius); x++) {
            for (int y = -int(blur_radius); y <= int(blur_radius); y++) {
                // Offset for neighboring pixels
                vec2 offset = vec2(float(x), float(y));

                // Calculate Gaussian weight
                float distance = length(offset);
                float weight = exp(-distance * distance / (2.0 * blur_radius * blur_radius));

                // Offset UV for color sampling
                vec2 sample_uv = shadow_uv + offset * (blur_radius / 100.0);

                // Check if the offset is within the texture bounds
                if (sample_uv.x >= 0.0 && sample_uv.x <= 1.0 && sample_uv.y >= 0.0 && sample_uv.y <= 1.0) {
                    vec4 sample_color = texture(TEXTURE, sample_uv); // Get the color
                    if (sample_color.a > 0.0) {
                        shadow_color += vec4(0.0, 0.0, 0.0, shadow_opacity) * weight; // Black color with weight
                        total_weight += weight; // Sum the weights
                    }
                }
            }
        }

        // Normalize the shadow color
        if (total_weight > 0.0) {
            shadow_color /= total_weight;
            COLOR = shadow_color; // Set the shadow color
        } else {
            COLOR = vec4(0.0, 0.0, 0.0, 0.0); // Full transparency
        }
    }
}

If your sprite has mipmaps, or can have mipmaps, you could sample that sprite again but at a lower mipmap level, then use that for your shadow pass, just probably have to adjust the value range so it’s well within 0 and 1.

Also if your sprite has extra space to include the shadow for the structure, have your alpha channel texture have the shadow gradient already there and use that in your shadow pass, but then when you officially mask out the base color for the sprite, just floor the alpha channel mask to get it to cut around the building properly.

Those would remove the need to do that kind of iteration which can be expensive.