Загрузка данных


// ============================================================
//  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);
}