Any easy way to draw 2d shadows over sprites but not to the background?

Godot Version



I’m not talking about shadows generated by lights, but simple shadows drawn as a mask on background objects, like this:

I found a simple shader that does this. The problem is that it draws shadows both over objects behind and over the background. An undesirable behavior if the background is a blue sky or the starry space. I think the problem is not in the shader, but that there is no way not to apply it to lower layers.

Here’s an example of what I’m talking about:

Above is the desired behavior, below is the undesired behavior.

The solution I found is a bit trichy. I have to put the scene with all sprites in a SubViewport with transparent bg flag set, then apply to the foreground objects a modified version of the shader that takes into account the background color of the viewport. Then the scene is draw over the background using a TextureRect whose texture is get from the SubViewport.

Here is my version of the shader:

shader_type canvas_item;
uniform vec2 offset = vec2(8.0, 8.0);
uniform vec4 modulate : source_color;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;
uniform vec4 background_color: source_color;

void fragment() {
	vec4 texture_col = texture(TEXTURE, UV);
	vec4 screen_col = texture(SCREEN_TEXTURE, SCREEN_UV);

	vec4 shadow = vec4(modulate.rgb, texture(TEXTURE, UV - offset * TEXTURE_PIXEL_SIZE).a * modulate.a);
	vec4 shadow_over_bg = mix(screen_col, shadow, screen_col.a);
	vec4 bg_color = texture(SCREEN_TEXTURE, SCREEN_UV);
	if (bg_color.rgba == background_color) {
		COLOR = texture_col;
	} else {
		COLOR = mix(shadow_over_bg, texture_col, texture_col.a);

It works. But I don’t like it.

I’m not very expert about Godot and game engines in general, so I imagine there might be a better solution. Anyone have a suggestion?