Загрузка данных
// ============================================================
// Starry Sky — атмосферное звёздное небо с переливами
// Godot 4.x, shader_type canvas_item
// Повесить на ColorRect (на весь экран) или любой Sprite2D.
// ============================================================
shader_type canvas_item;
// ---------- Настройки неба ----------
uniform vec4 sky_top : source_color = vec4(0.01, 0.01, 0.05, 1.0); // цвет вверху
uniform vec4 sky_bottom : source_color = vec4(0.05, 0.04, 0.16, 1.0); // цвет у горизонта
// ---------- Звёзды ----------
uniform float star_density : hint_range(0.0, 1.0) = 0.35; // сколько ячеек содержит звезду
uniform float star_scale : hint_range(10.0, 200.0) = 70.0; // размер сетки (больше = мельче звёзды)
uniform float twinkle_speed : hint_range(0.0, 10.0) = 2.0; // скорость мерцания
uniform float twinkle_amount : hint_range(0.0, 1.0) = 0.7; // глубина мерцания
uniform float star_glow : hint_range(0.5, 4.0) = 1.6; // мягкость ореола звезды
// ---------- Туманность / свечение ----------
uniform float nebula_intensity : hint_range(0.0, 2.0) = 0.8;
uniform float nebula_scale : hint_range(0.5, 10.0) = 3.0;
uniform float nebula_drift : hint_range(0.0, 0.2) = 0.02; // скорость дрейфа облаков
uniform vec4 nebula_color_a : source_color = vec4(0.15, 0.05, 0.35, 1.0); // фиолет
uniform vec4 nebula_color_b : source_color = vec4(0.00, 0.25, 0.35, 1.0); // бирюза
uniform vec4 nebula_color_c : source_color = vec4(0.35, 0.08, 0.25, 1.0); // маджента
// ---------- Переливы (иридесценция) ----------
uniform float shimmer_speed : hint_range(0.0, 2.0) = 0.25; // скорость переливов цвета
uniform float shimmer_strength : hint_range(0.0, 1.0) = 0.45; // сила переливов
// ============================================================
// Хэш и шум
// ============================================================
vec2 hash22(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
return fract(sin(p) * 43758.5453123);
}
float hash12(vec2 p) {
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123);
}
float value_noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f); // smoothstep-интерполяция
float a = hash12(i);
float b = hash12(i + vec2(1.0, 0.0));
float c = hash12(i + vec2(0.0, 1.0));
float d = hash12(i + vec2(1.0, 1.0));
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
// Фрактальный шум для туманности
float fbm(vec2 p) {
float v = 0.0;
float amp = 0.5;
mat2 rot = mat2(vec2(0.8, 0.6), vec2(-0.6, 0.8));
for (int i = 0; i < 5; i++) {
v += amp * value_noise(p);
p = rot * p * 2.03 + vec2(17.0);
amp *= 0.5;
}
return v;
}
// ============================================================
// Слой звёзд: сетка ячеек, в каждой — случайная звезда
// ============================================================
float star_layer(vec2 uv, float scale, float density, float seed, float t) {
vec2 gv = fract(uv * scale) - 0.5; // локальные координаты в ячейке
vec2 id = floor(uv * scale); // индекс ячейки
vec2 rnd = hash22(id + seed);
// не в каждой ячейке есть звезда
if (rnd.x > density) {
return 0.0;
}
// случайное смещение звезды внутри ячейки
vec2 offset = (rnd - 0.5) * 0.7;
float d = length(gv - offset);
// мерцание: у каждой звезды своя фаза и скорость
float phase = rnd.y * 6.2831;
float tw = sin(t * twinkle_speed * (0.5 + rnd.x) + phase) * 0.5 + 0.5;
float brightness = mix(1.0 - twinkle_amount, 1.0, tw);
// размер звезды тоже случайный
float size = mix(0.03, 0.11, rnd.y * rnd.y);
// ядро + мягкий ореол
float core = smoothstep(size, 0.0, d);
float halo = pow(max(0.0, 1.0 - d * (6.0 / star_glow)), 3.0) * 0.35;
return (core + halo) * brightness;
}
// Редкие крупные звёзды с лучами (дифракционный крест)
float bright_star_layer(vec2 uv, float scale, float t) {
vec2 gv = fract(uv * scale) - 0.5;
vec2 id = floor(uv * scale);
vec2 rnd = hash22(id + 91.7);
if (rnd.x > 0.06) { // очень редкие
return 0.0;
}
vec2 offset = (rnd - 0.5) * 0.5;
vec2 p = gv - offset;
float d = length(p);
float tw = sin(t * 1.3 + rnd.y * 6.2831) * 0.5 + 0.5;
float brightness = mix(0.55, 1.0, tw);
float core = smoothstep(0.06, 0.0, d);
// лучи по осям
float rays = max(0.0, 1.0 - abs(p.x * p.y) * 900.0);
rays *= smoothstep(0.35, 0.0, d);
return (core + rays * 0.5) * brightness;
}
// ============================================================
// Основной проход
// ============================================================
void fragment() {
vec2 uv = UV;
float t = TIME;
// --- фон: вертикальный градиент ---
vec3 col = mix(sky_top.rgb, sky_bottom.rgb, pow(uv.y, 1.4)).rgb;
// --- туманность: два слоя fbm, медленно дрейфующих ---
vec2 nuv = uv * nebula_scale;
float n1 = fbm(nuv + vec2(t * nebula_drift, 0.0));
float n2 = fbm(nuv * 1.7 - vec2(0.0, t * nebula_drift * 0.6) + 5.0);
float neb = smoothstep(0.35, 0.85, n1 * 0.65 + n2 * 0.35);
// переливающийся цвет туманности: плавное перетекание трёх оттенков
float hue_t = t * shimmer_speed;
float wa = sin(hue_t + n1 * 4.0) * 0.5 + 0.5;
float wb = sin(hue_t * 0.7 + n2 * 5.0 + 2.1) * 0.5 + 0.5;
vec3 neb_col = mix(nebula_color_a.rgb, nebula_color_b.rgb, wa);
neb_col = mix(neb_col, nebula_color_c.rgb, wb * shimmer_strength);
col += neb_col * neb * nebula_intensity;
// лёгкая дымка свечения поверх всего неба
col += neb_col * 0.06 * nebula_intensity;
// --- звёзды: три слоя параллакс-глубины ---
float stars = 0.0;
stars += star_layer(uv, star_scale, star_density, 1.0, t); // мелкие
stars += star_layer(uv, star_scale * 0.55, star_density * 0.8, 37.0, t) * 1.2; // средние
stars += star_layer(uv, star_scale * 0.30, star_density * 0.5, 73.0, t) * 1.5; // крупные
// звёзды чуть подкрашены переливом туманности рядом с ней
vec3 star_col = mix(vec3(1.0), neb_col * 2.0 + 0.6, neb * 0.5 * shimmer_strength);
col += star_col * stars;
// --- редкие яркие звёзды с лучами ---
float bright = bright_star_layer(uv, star_scale * 0.18, t);
col += vec3(0.9, 0.95, 1.0) * bright * 1.4;
// --- мягкое общее «дыхание» неба ---
col *= 1.0 + 0.03 * sin(t * 0.4);
// лёгкий тонемаппинг, чтобы яркие места не выгорали
col = col / (1.0 + col * 0.25);
COLOR = vec4(col, 1.0);
}