Files
g-world/shaders/menu_background.gdshader
T

85 lines
3.4 KiB
Plaintext

shader_type canvas_item;
// Анимированный фон главного меню: градиент + полярное сияние + звёзды + виньетка.
uniform vec4 color_top : source_color = vec4(0.035, 0.043, 0.098, 1.0);
uniform vec4 color_bottom : source_color = vec4(0.020, 0.106, 0.133, 1.0);
uniform vec4 aurora_a : source_color = vec4(0.180, 0.850, 0.760, 1.0);
uniform vec4 aurora_b : source_color = vec4(0.470, 0.360, 0.960, 1.0);
uniform float speed : hint_range(0.0, 0.3) = 0.035;
uniform float aurora_strength : hint_range(0.0, 2.0) = 0.55;
uniform float star_amount : hint_range(0.0, 1.0) = 0.45;
uniform float vignette_strength : hint_range(0.0, 1.0) = 0.65;
float hash21(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
// Мягкая волнистая полоса «сияния» на высоте center.
float aurora_band(vec2 uv, float t, float center, float freq, float thickness) {
float y = center
+ 0.090 * sin(uv.x * freq + t)
+ 0.050 * sin(uv.x * freq * 1.6 - t * 0.8)
+ 0.018 * sin(uv.x * freq * 2.7 + t * 0.5);
float d = abs(uv.y - y);
float band = smoothstep(thickness, 0.0, d);
return band * band;
}
// Звёздное поле. Три независимых хеша на ячейку: положение внутри ячейки,
// базовая яркость и характер мерцания. Без этого звёзды садятся на решётку
// и подмигивают синхронно, волной.
vec3 starfield(vec2 uv) {
vec2 grid = uv * vec2(190.0, 107.0);
vec2 cell = floor(grid);
vec2 local = fract(grid);
float h1 = hash21(cell);
float h2 = hash21(cell + 17.31);
float h3 = hash21(cell + 41.77);
float present = step(1.0 - star_amount * 0.045, h1);
// Смещение внутри ячейки убирает регулярность решётки.
vec2 offset = vec2(h2, h3) * 0.66 + 0.17;
float d = length(local - offset);
// Ядро плюс мягкий ореол — так звезда читается, не превращаясь в точку.
float radius = mix(0.13, 0.32, h3);
float shape = smoothstep(radius, 0.0, d) + 0.22 * smoothstep(radius * 3.0, 0.0, d);
// Две несоизмеримые частоты — рисунок мерцания не повторяется на глаз.
float phase = h1 * 62.83;
float flicker = 0.5 + 0.5 * (
0.62 * sin(TIME * (0.5 + h3 * 1.8) + phase)
+ 0.38 * sin(TIME * (0.31 + h2 * 1.1) * 1.618 + phase * 1.7)
);
// У части звёзд мерцание почти незаметно, у части — заметное.
float amplitude = 0.12 + 0.5 * h3;
float brightness = (0.30 + 0.70 * h2) * (1.0 - amplitude + amplitude * flicker);
vec3 tint = mix(vec3(0.74, 0.84, 1.0), vec3(1.0, 0.93, 0.80), h2);
return tint * present * shape * brightness;
}
void fragment() {
vec2 uv = UV;
float t = TIME * speed * 6.28318;
vec3 col = mix(color_top.rgb, color_bottom.rgb, smoothstep(0.0, 1.0, uv.y));
col += aurora_a.rgb * aurora_band(uv, t, 0.34, 4.0, 0.22) * aurora_strength;
col += aurora_b.rgb * aurora_band(uv, t * 0.75 + 2.0, 0.62, 3.0, 0.28) * aurora_strength * 0.75;
col += starfield(uv);
// Виньетка по краям кадра.
float v = distance(uv, vec2(0.5, 0.5));
col *= 1.0 - smoothstep(0.32, 0.95, v) * vignette_strength;
COLOR = vec4(col, 1.0);
}