Fake texture shadow
This is dead simple shader for complex 3D user interfaces. It creates crisp dynamic shadows by using two different cameras.
Idea
We have FG and BG visual layers. Background meshes should be on BG visual layer, while foreground meshes should be on FG visual layer. One camera renders both FG and BG visual layers, while the other renders only FG. In normal situation the cameras should have the same parameters except cull_mask. The second camera renders “shadow mask”.
Next we need some target to render this mask to. It’s mesh that is in front of background objects and behind foreground objects. Ideally it repeats background meshes’ shape near them. Shader is attached to this mesh.
The shader just takes “shadow mask”, offsets it, cuts environment background part and draws the result.
Example usage
You can see example node setup on the first screenshot and the result on the second (text and stripes are FG, buildings are BG). Subviewport renders background as transparant.
It should look cool with dynamic meshes. I’d make a person with moving traing background in poster-like style, if I’d be an artist.
Limitations:
- Shadows are bad on viewport conrners because camera do not see what is behind the corners. You may play with camera scale and orthographic mode to make it look pleasant though.
Shader code
shader_type spatial;
render_mode unshaded;
// We need to rednder "shadow" that overlaps other objects and not backgrounnd.
// If it's not overlapping then it renders transparent.
const float ALPHA_UNION_CUT = 1.999;
uniform sampler2D viewport_tex: hint_screen_texture, repeat_disable;
uniform sampler2D shadow_mask_tex: source_color, repeat_disable;
uniform vec4 shadow_color: source_color;
uniform vec2 shadow_offset;
void fragment() {
float viewport_alpha = texture(viewport_tex, SCREEN_UV).a;
float shadow_mask = texture(shadow_mask_tex, SCREEN_UV + shadow_offset).a;
ALBEDO = shadow_color.rgb;
ALPHA = shadow_color.a * step(ALPHA_UNION_CUT, viewport_alpha + shadow_mask);
}


