OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / addons / nubis_clouds / shaders / cloud_shadow_ground.gdshader

61 lines · gdshader ref:
// Ground shader with analytical cloud shadows
// Projects fragment position toward sun to find cloud intersection,
// then samples noise at that position to darken the ground.
shader_type spatial;

uniform vec3 ground_color : source_color = vec3(0.3, 0.35, 0.2);
uniform sampler3D perlworlnoise : filter_linear_mipmap, repeat_enable;
uniform sampler2D weather_map : filter_linear_mipmap, repeat_enable;
uniform float cloud_coverage : hint_range(0.0, 1.0) = 0.35;
uniform float cloud_altitude : hint_range(100.0, 5000.0) = 1500.0;
uniform float shadow_strength : hint_range(0.0, 1.0) = 0.5;
uniform float cloud_time_scale : hint_range(0.0, 20.0) = 2.0;
uniform vec2 cloud_direction = vec2(1.0, 0.0);

float remap(float v, float lo, float hi, float nlo, float nhi) {
	return nlo + (v - lo) / (hi - lo) * (nhi - nlo);
}

float cloud_shadow(vec3 world_pos, vec3 light_dir) {
	// Project world position toward sun to cloud altitude
	if (light_dir.y <= 0.001) return 0.0;  // sun below horizon
	float t = (cloud_altitude - world_pos.y) / light_dir.y;
	vec3 cloud_pos = world_pos + light_dir * t;

	// Wind offset
	float wind_t = 0.003 * TIME * cloud_time_scale;
	vec2 weather_offset = vec2(wind_t * cloud_direction.x, wind_t * cloud_direction.y);

	// Sample weather map for coverage
	float weather_scale = 0.00006;
	float weather_b = texture(weather_map, cloud_pos.xz * weather_scale + 0.5 + weather_offset).b;

	// Sample base noise
	float noise_scale = 0.00008;
	cloud_pos.x += 10.0 * TIME * cloud_time_scale;
	vec4 n = textureLod(perlworlnoise, cloud_pos * noise_scale, 0.0);
	float fbm = n.g * 0.625 + n.b * 0.25 + n.a * 0.125;
	float base = remap(n.r, -(1.0 - fbm), 1.0, 0.0, 1.0);

	float cov = cloud_coverage * weather_b;
	base = remap(base, 1.0 - cov, 1.0, 0.0, 1.0) * cov;

	return clamp(base, 0.0, 1.0) * shadow_strength;
}

varying vec3 world_position;

void vertex() {
	world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}

void fragment() {
	ALBEDO = ground_color;
}

void light() {
	vec3 light_world = normalize((INV_VIEW_MATRIX * vec4(LIGHT, 0.0)).xyz);
	float shadow = cloud_shadow(world_position, light_world);
	DIFFUSE_LIGHT += ALBEDO * ATTENUATION * LIGHT_COLOR * max(dot(NORMAL, LIGHT), 0.0) * (1.0 - shadow);
}