Files
autgame/menus/assets/shaders/tent_lights.gdshader
T

131 lines
5.3 KiB
Plaintext

shader_type canvas_item;
// Tendone del menu: chase delle lucine delle garlande, attivo solo in hover.
// Il chase replica l'animazione sorgente (animazione_tendone.gif, 12,5 fps):
// periodo 6 frame, 3 fasi da 2 frame; ogni lampadina fa rampa per 2 frame,
// brilla a pieno intensità per 2 frame e resta spenta per 2 frame.
// Lato sinistro: l'onda sale dal fondo verso il picco (fasi [4,2,0] per i mod 3).
// Lato destro: l'onda scende dal picco al fondo (fasi [0,2,4] per i mod 3);
// al picco L0 (fase 0) precede R0 (fase 1) di 2 frame, come nella GIF.
uniform float hover_strength : hint_range(0.0, 1.0) = 0.0;
uniform vec2 star_center = vec2(0.50, 0.13);
uniform float drift_strength : hint_range(0.0, 4.0) = 0.65;
uniform float drift_speed : hint_range(0.0, 2.0) = 0.20;
// Intensità del chase lucine: 0 = spento a riposo, 1.0 = attivo in hover.
uniform float garland_strength : hint_range(0.0, 1.0) = 0.0;
// FPS sorgente dell'animazione (GIF a 8 centesimi di secondo per frame).
uniform float garland_fps : hint_range(1.0, 60.0) = 12.5;
// Frame assoluto con cui congelare il chase (debug/catture); -1 = tempo reale.
uniform float garland_freeze_frame = -1.0;
// Nucleo della lampadina accesa e colore dell'alone, campionati dalla GIF.
const vec3 GOLD_CORE = vec3(0.945, 0.80, 0.385);
const vec3 GOLD_HALO = vec3(1.0, 0.78, 0.35);
// Posizioni lampadina in UV texture (canvas 880x750) + offset di fase in frame
// nel ciclo di 6: z = frame di inizio rampa. L0..L9 dal picco al fondo sinistro,
// R0..R9 dal picco al fondo destro.
const vec3 bulbs[20] = vec3[20](
// garlanda sinistra: onda che sale
vec3(0.4500, 0.2893, 4.0), vec3(0.4330, 0.3187, 2.0), vec3(0.4125, 0.3453, 0.0),
vec3(0.3875, 0.3747, 4.0), vec3(0.3591, 0.4080, 2.0), vec3(0.3341, 0.4360, 0.0),
vec3(0.3000, 0.4693, 4.0), vec3(0.2670, 0.5013, 2.0), vec3(0.2295, 0.5307, 0.0),
vec3(0.1920, 0.5587, 4.0),
// garlanda destra: onda che scende
vec3(0.5307, 0.3000, 0.0), vec3(0.5443, 0.3333, 2.0), vec3(0.5648, 0.3573, 4.0),
vec3(0.5852, 0.3840, 0.0), vec3(0.6205, 0.4253, 2.0), vec3(0.6420, 0.4573, 4.0),
vec3(0.6761, 0.4880, 0.0), vec3(0.7114, 0.5160, 2.0), vec3(0.7466, 0.5427, 4.0),
vec3(0.7773, 0.5613, 0.0)
);
// 4 grandi luci sui punti di ancoraggio delle funi a terra lungo la balza:
// 0: Esterno Sinistro (131.3, 502.1) -> fase 4 (in fase con L9 in fondo a sinistra)
// 1: Palo/Fune SX Ingresso (306.5, 544.1) -> fase 0
// 2: Palo/Fune DX Ingresso (558.6, 550.7) -> fase 2
// 3: Esterno Destro (737.2, 499.3) -> fase 4 (in fase con la discesa a destra)
const vec3 anchor_bulbs[4] = vec3[4](
vec3(0.1492, 0.6695, 4.0),
vec3(0.3483, 0.7255, 0.0),
vec3(0.6348, 0.7342, 2.0),
vec3(0.8378, 0.6657, 4.0)
);
// Intensità nel ciclo di 6 frame della singola lampadina (d = frame dalla rampa),
// ricavata dalle aree misurate sui frame della GIF: ~25%, ~50%, pieno, pieno, 0, 0.
float chase_intensity(float d) {
if (d < 1.0) {
return 0.3;
}
if (d < 2.0) {
return 0.6;
}
if (d < 3.0) {
return 1.0;
}
if (d < 4.0) {
return 0.95;
}
return 0.0;
}
void vertex() {
float wave = sin(TIME * drift_speed + VERTEX.y * 0.012) * drift_strength;
VERTEX.x += wave * (UV.y * 0.7 + 0.3);
}
void fragment() {
vec4 color = texture(TEXTURE, UV);
// Maschera morbida limitata alla stella in cima al tendone, non al tendone.
vec2 aspect_uv = (UV - star_center) * vec2(1.0, 1.35);
float star_area = 1.0 - smoothstep(0.105, 0.185, length(aspect_uv));
float pulse = 0.88 + 0.12 * sin(TIME * 5.0);
vec3 gold_glow = vec3(1.0, 0.70, 0.14) * star_area * hover_strength * pulse;
color.rgb += gold_glow * color.a;
// Chase lucine: sincronizzato a 12,5 fps come la GIF sorgente.
if (garland_strength > 0.001) {
float frame_time = TIME * garland_fps;
if (garland_freeze_frame >= 0.0) {
frame_time = garland_freeze_frame;
}
float cycle = mod(floor(frame_time), 6.0);
vec2 px = UV * vec2(880.0, 750.0);
for (int i = 0; i < 20; i++) {
float d = mod(cycle - bulbs[i].z + 6.0, 6.0);
float intensity = chase_intensity(d);
if (intensity <= 0.0) {
continue;
}
float r = length(px - bulbs[i].xy * vec2(880.0, 750.0));
// Nucleo pieno ~6px + alone ampio e diffuso fino a ~25px (come nella GIF).
float core = 1.0 - smoothstep(3.0, 8.0, r);
float halo = exp(-r / 12.0);
float ga = clamp(intensity * garland_strength, 0.0, 1.0);
// Il nucleo porta la lampadina all'oro pieno della GIF.
color.rgb = mix(color.rgb, GOLD_CORE, core * ga);
// Alone caldo additivo solo attorno al nucleo (senza sforare sul nucleo,
// altrimenti il clamp sbiadisce l'oro verso il bianco).
color.rgb += GOLD_HALO * (halo * ga * 0.7 * (1.0 - core));
color.a = max(color.a, halo * ga * 0.5);
}
// 4 grandi luci sui punti di ancoraggio delle funi (intermittenti a inseguimento con ritmo proprio)
for (int j = 0; j < 4; j++) {
float d = mod(cycle - anchor_bulbs[j].z + 6.0, 6.0);
float intensity = chase_intensity(d);
if (intensity <= 0.0) {
continue;
}
float r = length(px - anchor_bulbs[j].xy * vec2(880.0, 750.0));
float core = 1.0 - smoothstep(4.0, 10.0, r);
float halo = exp(-r / 15.0);
float ga = clamp(intensity * garland_strength, 0.0, 1.0);
color.rgb = mix(color.rgb, GOLD_CORE, core * ga);
color.rgb += GOLD_HALO * (halo * ga * 0.8 * (1.0 - core));
color.a = max(color.a, halo * ga * 0.6);
}
}
color.rgb = min(color.rgb, vec3(1.0));
COLOR = color;
}