How to Make Texture Stretch in Direction of Light

Godot Version

4.6.1

Question

I’m trying to modify a shader I’m making for my game to have “cloud shadows”. Since my game is top down, I’m simulating the existence of shadows with a scrolling noise texture plugged into the ATTENUATION of the light() function of my shader.

float attenuation = 1.0f;
float cloud_cover = texture(cloud_noise_texture, (instance_pos.xz + (cloud_scroll_speed * TIME)) * (cloud_cover_scale)).r;
cloud_cover -= cloud_cover_intensity;
if (use_attenuation) {
	attenuation = min(ATTENUATION, cloud_cover);
}

But I’d like to make this “shadows” stretch in the direction of the directional light I have in my scene acting as the sun, to simulate how they would look like during sunrise and sunset. Ideally, I would be able to change how much of an impact light direction has, but I can’t even make it stretch correctly.

1 Like

Project the light direction vector to the ground plane. Scale u and v proportionally to that vector’s x and z.

2 Likes

This seems like a neat effect.

1 Like

For projecting the LIGHT I’m using (INV_VIEW_MATRIX * vec4(LIGHT, 1.0)) to convert the screen view LIGHT vector to a world view one, but I’m struggling with this second part. Adding, multiplying, or dividing the projection result to the cloud_cover UV simply scrolls the texture when the directional light is rotated.

I’m still quite inexperienced with shaders in general, so I may be missing something simple…

Can you post a visual mockup of how it’s supposed to look and behave?

This is the basic idea behind what I’m trying to do. I want it to behave as if there actually were clouds in the sky producing shadows. When the sun went low, they would start to slightly move and stretch in the direction the light is shinning at, just like any other object’s shadow.

What’s the point in “moving” them if you don’t see the actual casters? Just scale the UVs proportionally to the components of a projection of the light vector onto the horizontal plane.

1 Like

Say the clouds are all the same height.

Now just imagine a cylinder cut at an angle, the cylinder is a shaft of sunlight and the cut is the ground.

When the cylinder is at a sharper angle, the cut becomes longer.

Then, on paper you can see that the cross section width of the cylinder is

d = 2 * radius

The length you want is a hypoteneuse of a right angle triangle with angle theta_sun

Now thats

R cos theta_sun =2 × r

so

R = 2 × r / cos theta_sun

I could be wrong and im not using a bit of paper, but from here you should be able to deduce the scale factor yourself, using a percentage.

That actually did the trick! I rewrote the UV code to allow me to modify the final Y/V component independently and multiply it by the Y component of the LIGHT vector (corrected for world space).

Here is the full code, if anyone is interested:

// Attenuation.
float attenuation = 1.0f;

// Convert LIGHT from view space to world space
vec3 LIGHT_world_space = (INV_VIEW_MATRIX * vec4(LIGHT, 0.0)).xyz;

// Manipulate cloud noise UV values
vec2 cloud_uv = (instance_pos.xz + (cloud_scroll_speed * TIME)) * (cloud_cover_scale);
// Stretch UV in direction of the sun LIGHT
cloud_uv = vec2(cloud_uv.x, cloud_uv.y * LIGHT_world_space.y);

//Sample texture value for current pixel 
float cloud_cover = texture(cloud_noise_texture, cloud_uv).r;

// Threshold value for crisp shadows 
if (cloud_cover >= cloud_cover_threshold) {
	cloud_cover = 0.0;
} else {
	cloud_cover = 1.0;
}

// Apply a shadow if it exists
if (use_attenuation) {
	attenuation = min(ATTENUATION, cloud_cover);
}

The above code is part of a toon shader I’m making for my game. This samples a noise texture following either the pixel world position (for the ground plane) or the object’s position (for grass and leaves) with a possible scrolling velocity and scale factor for further tweaking.

2 Likes

Here is a showcase of how it ended up. Still have a bit of polishing to do, but thank you all for helping!

2 Likes

Looks good!

You should share it on Godot Shaders.

1 Like

Thanks! Might add it some day, but I don’t think it’s good enough, yet. If anyone wants an excellent starting point, mine’s a modified version of the Flexible Toon Shader by atzuk4451