Files
mod_interface/shaders/timed_sprite.gdshader
2026-09-10 10:59:37 +03:00

128 lines
4.0 KiB
Plaintext

shader_type canvas_item;
render_mode blend_premul_alpha;
uniform sampler2D depth_mask : source_color, filter_linear;
uniform sampler2D albedo_map : source_color, filter_linear;
uniform float flicker_speed : hint_range(0.0, 100.0) = 5.0;
uniform float flicker_strength : hint_range(0.0, 1.0) = 0.3;
uniform float flicker_scale : hint_range(0.0, 10.0) = 1.0;
uniform bool use_time = true;
uniform vec4 day_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform vec4 morning_color : source_color = vec4(0.8207547, 0.6465379, 0.8050903, 1.0);
uniform vec4 night_color : source_color = vec4(0.0, 0.13673696, 0.20754719, 1.0);
uniform vec4 evening_color : source_color = vec4(0.81671757, 0.7075472, 0.9433962, 1.0);
uniform vec4 time_weights = vec4(0.0, 1.0, 0.0, 0.0);
uniform float light_intensity : hint_range(0.0, 10.0) = 2.0;
uniform float light_falloff : hint_range(0.0, 10.0) = 3.0;
uniform float light_radius_scale : hint_range(0.0, 10.0) = 1.0;
uniform vec2 light_positions[11];
uniform vec4 light_colors[11];
uniform float light_radii[11];
uniform float light_influence[11];
uniform int light_count;
varying vec2 world_pos;
float rand(vec2 co) {
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}
vec3 calculate_light_color(vec2 wp, out float total_influence) {
vec3 combined_color = vec3(0.0, 0.0, 0.0);
total_influence = 0.0;
for (int i = 0; i < 11; i++) {
if (i >= light_count)
break;
vec2 light_pos = light_positions[i];
float light_radius = light_radii[i] * light_radius_scale;
vec3 light_col = light_colors[i].rgb;
float dist = distance(wp, light_pos);
float influence = clamp(1.0 - dist / light_radius, 0.0, 1.0);
// Avoid pow with negative base
if (influence <= 0.0)
continue;
influence = pow(influence, light_falloff);
float flicker_seed = light_pos.x * 1.357 + light_pos.y * 2.468 + float(i) * 3.579;
float discrete_time = floor(TIME * flicker_speed * 3.0 + flicker_seed) / 3.0;
float t1 = discrete_time * 2.0;
float t2 = discrete_time * 3.0 + 1.2;
float t3 = discrete_time * 4.0 + 2.4;
float flicker1 = floor((sin(t1) * 0.5 + 0.5) * 4.0) / 3.0;
float flicker2 = floor((sin(t2) * 0.3 + 0.5) * 3.0) / 2.0;
float flicker3 = floor((sin(t3) * 0.2 + 0.5) * 3.0) / 2.0;
float flicker = flicker1 * 0.5 + flicker2 * 0.3 + flicker3 * 0.2;
float noise_seed = floor(TIME * flicker_speed * 2.0 + flicker_seed);
float noise_val = rand(vec2(noise_seed, flicker_seed)) * 0.15;
flicker = floor((flicker + noise_val) * 5.0) / 4.0;
flicker = clamp(flicker, 0.0, 1.0);
float flicker_factor = 0.7 + flicker * 0.6 * flicker_strength;
flicker_factor = floor(flicker_factor * 8.0) / 7.0;
influence *= flicker_factor;
combined_color += light_col * influence * light_intensity * light_influence[i];
total_influence += influence * light_intensity * light_influence[i];
}
return combined_color;
}
void vertex() {
world_pos = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}
void fragment() {
vec4 color = texture(TEXTURE, UV) * COLOR;
float a = color.a;
float depth = texture(depth_mask, UV).r;
float albedo = texture(albedo_map, UV).r;
#ifdef ALPHA_CLIP
if (color.a < 0.001)
discard;
#endif
if (!use_time) {
COLOR = color;
} else {
vec4 weights = time_weights;
vec4 time_color = morning_color * weights.x
+ day_color * weights.y
+ evening_color * weights.z
+ night_color * weights.w;
float total_influence;
vec3 light_col = calculate_light_color(world_pos, total_influence);
total_influence = clamp(total_influence, 0.0, 1.0);
float light_infl = clamp(mix(light_col.r, 0.0, weights.y + weights.x + weights.z) * depth, 0.0, 1.0);
float pixel_luma = max(dot(color.rgb, vec3(0.299, 0.587, 0.114)), 0.01);
float target_luma = max(albedo, pixel_luma);
float lift = mix(1.0, target_luma / pixel_luma, light_infl);
vec3 lit_result = min(color.rgb * lift * light_col, 1.0);
COLOR.rgb = mix(color.rgb * time_color.rgb, lit_result, light_infl);
COLOR.a = a;
}
}