63 lines
2.7 KiB
Plaintext
63 lines
2.7 KiB
Plaintext
shader_type canvas_item;
|
|
render_mode unshaded;
|
|
|
|
uniform float elapsed = 0.0;
|
|
|
|
float hash(vec2 p) {
|
|
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
|
|
}
|
|
float noise(vec2 p) {
|
|
vec2 i = floor(p);
|
|
vec2 f = fract(p);
|
|
f = f * f * (3.0 - 2.0 * f);
|
|
return mix(mix(hash(i), hash(i + vec2(1, 0)), f.x),
|
|
mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), f.x), f.y);
|
|
}
|
|
float turbulence(vec2 p) {
|
|
return noise(p) * 0.55 + noise(p * 2.07) * 0.28 + noise(p * 4.13) * 0.17;
|
|
}
|
|
void fragment() {
|
|
vec2 p = (UV - 0.5) * 2.0;
|
|
float r = length(p);
|
|
float a = atan(p.y, p.x);
|
|
float t = elapsed;
|
|
float reveal = smoothstep(0.0, 1.2, t);
|
|
float pulse = 1.0 + 0.012 * sin(t * 2.1);
|
|
float radius = r / pulse;
|
|
// Use circular coordinates for seamless turbulent filaments.
|
|
float twist = a + 2.6 * log(max(radius, 0.035)) - t * 0.65;
|
|
vec2 flow = vec2(cos(twist), sin(twist));
|
|
float clouds = turbulence(flow * 5.0 + vec2(radius * 13.0, -t * 0.3));
|
|
float filaments = pow(max(0.0, sin(twist * 7.0 + clouds * 5.0)), 5.0);
|
|
float disc = exp(-pow((radius - 0.46) / 0.125, 2.0));
|
|
float rim_r = 0.432 + 0.008 * sin(a * 6.0 - t * 1.4) + (clouds - 0.5) * 0.017;
|
|
float rim = exp(-abs(radius - rim_r) * 170.0);
|
|
float bloom = exp(-abs(radius - rim_r) * 25.0);
|
|
float halo = exp(-pow(radius / 0.66, 4.0));
|
|
vec3 cyan = vec3(0.16, 0.73, 1.0);
|
|
vec3 violet = vec3(0.40, 0.15, 0.93);
|
|
vec3 tint = mix(violet, cyan, 0.5 + 0.5 * sin(twist * 2.0 + t * 0.3));
|
|
vec3 color = tint * disc * (0.18 + clouds * 0.55 + filaments * 0.85);
|
|
color += cyan * bloom * 0.3 + vec3(0.63, 0.92, 1.0) * rim * 1.5;
|
|
color += violet * halo * 0.055;
|
|
// A dark throat with contracting spiral bands suggests a deep tunnel.
|
|
float inside = 1.0 - smoothstep(0.37, 0.425, radius);
|
|
float depth = -log(max(radius / 0.425, 0.015));
|
|
float tunnel = pow(max(0.0, sin(depth * 16.0 - t * 3.3 + a * 2.0)), 12.0);
|
|
float throat_fade = smoothstep(0.035, 0.3, radius);
|
|
vec3 throat = vec3(0.003, 0.006, 0.026);
|
|
throat += mix(violet, cyan, radius / 0.425) * tunnel * throat_fade * 0.22;
|
|
throat += cyan * pow(max(0.0, sin(twist * 5.0 + clouds * 2.0)), 14.0) * throat_fade * 0.11;
|
|
color = mix(color, throat, inside);
|
|
// Orbiting pinpoints and their short luminous trails, outside the event horizon.
|
|
float orbit_angle = a - t * 0.24;
|
|
vec2 orbit = vec2(cos(orbit_angle), sin(orbit_angle)) * radius * 43.0;
|
|
float sparks = pow(turbulence(orbit), 18.0) * 32.0;
|
|
sparks *= smoothstep(0.45, 0.52, radius) * (1.0 - smoothstep(0.62, 0.86, radius));
|
|
color += vec3(0.56, 0.83, 1.0) * sparks;
|
|
float alpha = max(inside, max(disc * (0.5 + clouds * 0.5), bloom * 0.8));
|
|
alpha = max(alpha, halo * 0.1 + sparks);
|
|
alpha *= (1.0 - smoothstep(0.84, 0.98, radius)) * reveal;
|
|
COLOR = vec4(color, clamp(alpha, 0.0, 1.0));
|
|
}
|