How to change shadow opacity in gdshader

Godot Version

4.4

Question

Hello everyone! For the last couple days I have been trying to create moving cloud shadows in my 3d game. Right now I have a plain mesh with a scrolling and evolving 2d noise texture hovering above my world that casts shadows based on a threshold value for alpha_scissor_cutoff. However I would like for these cloud shadows specifically to have a different opacity with a select number of bands based on the noise texture (see the picture below for the style im trying to recreate). Im not sure if i should do something in the light or fragment function and how to change/fake the shadow opacity. Any help is greatly appreciated! :)

CODE:

shader_type spatial;

uniform sampler2D noise : filter_linear;
uniform sampler2D bump : hint_normal;
uniform float threshold : hint_range(0.0, 1.0) = 0.5;
uniform float speed : hint_range(0.0, 16.0) = 1.0;
uniform vec2 uv_scale = vec2(1.0, 1.0);
uniform float evolve_speed : hint_range(0.0, 2.0) = 0.1;

varying vec2 uv_normal;

void vertex()
{
	float fps = 30.0;
	float quantized_time = floor(TIME * fps) / fps;

	uv_normal = UV + quantized_time;
	UV = (UV * uv_scale) + quantized_time * speed;
}

void fragment(){
	vec3 distortion = texture(bump, uv_normal).rgb;

	float base_noise = texture(noise, UV + distortion.xy).r;
	
	vec2 evolved_uv = UV + distortion.xy + vec2(0.0, TIME * evolve_speed);
	float scrolling_noise = texture(noise, evolved_uv).r;

	float final_noise = mix(base_noise, scrolling_noise, 0.2);

	ALPHA = final_noise;
	ALPHA_SCISSOR_THRESHOLD = threshold;
}

Sounds like you do not want to use ALPHA_SCISSOR_THRESHOLD if you intend to change opacity, maybe a step function?

Yeah you’re right! I already have a normal toon shader for objects in the world that works that way so the stepping is no problem. Im just not sure in the above shader what i should access to change the opacity.

You can set your noise texture to use constant interpolation

Thanks a lot :star_struck:! The texture itself now looks way better! But how do I get the texture to work like a shadow now? You can see my setup in the image: if I don’t use ALPHA_SCISSOR_THRESHOLD then there are no shadows at all right now.

I think Godot only supports 1-bit shadow maps for dynamic lights/shadows, you may need to take another approach than physically lighting the texture. Maybe you can use a shader on your map or the mesh quad to overlay the clouds as a fake shadow? A spotlight could project a multi-color noise texture, but not a shader so you’d have to animate the noise or spotlight seperately.

There is some talk on a open issue about semi-transparent objects casting shadows, but then alpha-hash would get you a similar but worse effect.

1 Like

This is what I’m using.

Similar setup to yours. I am also trying to recreate a similar style to the t3ssel8r.

As @gertkeno mentioned as one of the solutions (i overlay the quad with the shader to take a zenithal overview, rendered to a texture, and use that texture for the floor).

shader_type spatial;
render_mode unshaded, depth_draw_always, cull_disabled;

uniform sampler2D cloud_tex : source_color;

uniform vec2 scroll_speed = vec2(0.01, 0.01);
uniform float scale = 0.02;
uniform float shadow_strength = 0.3;

void fragment() {
vec2 uv = UV * scale + scroll_speed * TIME;
float noise = texture(cloud_tex, uv).r;
if (noise > 0.5) {
ALPHA = 0.0;
} else {
ALPHA = noise * shadow_strength;
}
ALBEDO = vec3(0.0);
}

I would be very interested in seeing how you managed the grass.
I had to jump through hoops to do it.

Hey there!

Sorry for the late reply.

So I’m using a multimeshinstance3d node with a quad mesh material that has a billboarding shader on it. You compute this by getting the camera’s local scope normalized z first. Then you use the cross product to get the x and for the y you can just do a normalized up vector. Finally you use those 3 values to make a rotation matrix and apply it to the vertex. If you have other logic for e.g. wind based animations in the vertex function make sure to apply those first otherwise the vector logic glitches out when you try to rotate the camera.

I hope this helped!