0.00
60.0 fps
blackhole
enjoy. (you need to make some optimizations)
Log in to post a comment.
#version 300 es
precision highp float;
uniform float iTime;
uniform vec2 iResolution;
uniform vec4 iMouse;
in vec2 vScreen;
out vec4 fragColor;
const float PI = 3.14159265359;
const int ITERATIONS = 240;
const float INV_ITERATIONS = 0.004166666667;
const float FAR_DISTANCE = 15.0;
const vec3 MAIN_COLOR = vec3(1.0);
const vec3 WARM_LIGHT = vec3(1.0, 0.78, 0.42);
void mainImage(out vec4 outColor, in vec2 fragCoord);
void main()
{
vec2 fragCoord = (vScreen * 0.5 + 0.5) * iResolution;
mainImage(fragColor, fragCoord);
}
float saturate(float value)
{
return clamp(value, 0.0, 1.0);
}
vec3 saturate(vec3 value)
{
return clamp(value, vec3(0.0), vec3(1.0));
}
float hash31(vec3 value)
{
return fract(sin(dot(value, vec3(127.1, 311.7, 74.7))) * 43758.5453123);
}
float rand(vec2 coord)
{
return fract(sin(dot(coord, vec2(12.9898, 78.233))) * 43758.5453);
}
float noise(vec3 point)
{
vec3 cell = floor(point);
vec3 local = fract(point);
local = local * local * (3.0 - 2.0 * local);
float n000 = hash31(cell + vec3(0.0, 0.0, 0.0));
float n100 = hash31(cell + vec3(1.0, 0.0, 0.0));
float n010 = hash31(cell + vec3(0.0, 1.0, 0.0));
float n110 = hash31(cell + vec3(1.0, 1.0, 0.0));
float n001 = hash31(cell + vec3(0.0, 0.0, 1.0));
float n101 = hash31(cell + vec3(1.0, 0.0, 1.0));
float n011 = hash31(cell + vec3(0.0, 1.0, 1.0));
float n111 = hash31(cell + vec3(1.0, 1.0, 1.0));
float x00 = mix(n000, n100, local.x);
float x10 = mix(n010, n110, local.x);
float x01 = mix(n001, n101, local.x);
float x11 = mix(n011, n111, local.x);
float y0 = mix(x00, x10, local.y);
float y1 = mix(x01, x11, local.y);
return mix(y0, y1, local.z) * 2.0 - 1.0;
}
float fbm(vec3 point)
{
float amplitude = 0.52;
float sum = 0.0;
float normalizer = 0.0;
for (int i = 0; i < 5; i++)
{
sum += (noise(point) * 0.5 + 0.5) * amplitude;
normalizer += amplitude;
point = point * 2.03 + vec3(11.7, 5.3, 17.1);
amplitude *= 0.5;
}
return sum / normalizer;
}
float discCurve(float x)
{
float x2 = x * x;
float x4 = x2 * x2;
return x4 * (1.0 - x) * (8.8 + 2.4 * x);
}
float sdTorus(vec3 point, vec2 torus)
{
vec2 q = vec2(length(point.xz) - torus.x, point.y);
return length(q) - torus.y;
}
vec3 rotate(vec3 point, float x, float y, float z)
{
mat3 matX = mat3(
1.0, 0.0, 0.0,
0.0, cos(x), sin(x),
0.0, -sin(x), cos(x)
);
mat3 matY = mat3(
cos(y), 0.0, -sin(y),
0.0, 1.0, 0.0,
sin(y), 0.0, cos(y)
);
mat3 matZ = mat3(
cos(z), sin(z), 0.0,
-sin(z), cos(z), 0.0,
0.0, 0.0, 1.0
);
return matY * matZ * matX * point;
}
vec3 starField(vec3 direction)
{
vec3 p = normalize(direction);
vec2 uv = vec2(atan(p.x, p.z) / (2.0 * PI) + 0.5, asin(p.y) / PI + 0.5);
vec2 grid = floor(uv * vec2(900.0, 450.0));
float cell = rand(grid);
float star = smoothstep(0.997, 1.0, cell);
float twinkle = 0.55 + 0.45 * sin(iTime * (1.5 + cell * 5.0) + cell * 30.0);
vec3 color = mix(vec3(0.82, 0.88, 1.0), vec3(1.0, 0.86, 0.62), rand(grid + 13.0));
return color * star * twinkle * 0.45;
}
void rotateCamera(inout vec3 rayDir, inout vec3 cameraPos)
{
vec2 mouse = iMouse.xy / max(iResolution.xy, vec2(1.0));
if (iMouse.z <= 0.0)
{
mouse = vec2(0.35, 0.35);
}
vec3 angle = vec3(mouse.y * 0.05 + 0.05, 1.0 + mouse.x, -0.45);
rayDir = rotate(rayDir, angle.x, angle.y, angle.z);
cameraPos = rotate(cameraPos, angle.x, angle.y, angle.z);
}
void warpSpace(inout vec3 rayDir, vec3 rayPos)
{
float distSq = dot(rayPos, rayPos);
float warpFactor = 1.0 / (distSq + 0.000001);
vec3 singularityVector = normalize(-rayPos);
float warpAmount = 5.0;
rayDir = normalize(rayDir + singularityVector * warpFactor * warpAmount * INV_ITERATIONS);
}
void addHaze(inout vec3 color, vec3 rayPos, float alpha)
{
float torusDist = abs(sdTorus(rayPos + vec3(0.0, -0.05, 0.0), vec2(1.0, 0.01)));
float torusDistSq = torusDist * torusDist;
float rayLength = length(rayPos);
float sharpBloom = 1.0 / (torusDistSq + 0.001);
float softBloom = 1.0 / (torusDistSq * 0.22 + 0.018);
float wideBloom = 1.0 / (torusDistSq * 0.045 + 0.09);
float haloDist = abs(rayLength - 1.05);
float photonHalo = 1.0 / (haloDist * haloDist * 28.0 + abs(rayPos.y) * 14.0 + 1.0);
float occlusion = rayLength < 0.5 ? 0.0 : 1.0;
vec3 bloomColor = MAIN_COLOR * sharpBloom * 2.15;
bloomColor += WARM_LIGHT * softBloom * 0.48;
bloomColor += vec3(1.0, 0.68, 0.28) * wideBloom * 0.13;
bloomColor += vec3(1.0, 0.86, 0.58) * photonHalo * 0.7;
color += bloomColor * occlusion * (2.9 * INV_ITERATIONS) * (1.0 - alpha);
}
void addGasDisc(inout vec3 color, inout float alpha, vec3 rayPos, vec3 rayDir)
{
float discRadius = 3.2;
float discWidth = 5.3;
float discInner = discRadius - discWidth * 0.5;
float distFromCenter = length(rayPos);
float distFromDisc = rayPos.y;
float radialGradient = 1.0 - saturate((distFromCenter - discInner) / discWidth * 0.5);
float discMask = discCurve(radialGradient);
float coverage = discMask;
float discThickness = 0.1 * radialGradient;
coverage *= saturate(1.0 - abs(distFromDisc) / max(discThickness, 0.0001));
float fadeBase = abs(distFromCenter - discInner) + 0.4;
float fadeSq = fadeBase * fadeBase;
float fade = fadeSq * fadeSq * 0.04;
float bloomFactor = 1.0 / (distFromDisc * distFromDisc * 40.0 + fade + 0.00002);
float inverseGradient = 1.0 - radialGradient;
float dustGlow = 1.0 / (inverseGradient * inverseGradient * 290.0 + 0.002);
vec3 hotCore = WARM_LIGHT * dustGlow * 8.2;
float radialGradientSq = radialGradient * radialGradient;
vec3 bloom = MAIN_COLOR * bloomFactor * sqrt(bloomFactor);
bloom *= mix(vec3(1.65, 0.98, 0.62), vec3(1.0, 0.84, 0.54), vec3(radialGradientSq));
bloom *= mix(vec3(1.7, 0.48, 0.09), vec3(1.05, 0.92, 0.72), vec3(sqrt(radialGradient)));
vec3 dustColor = mix(hotCore, bloom * 150.0, saturate(1.0 - coverage));
coverage = saturate(coverage * 0.7 + bloomFactor * bloomFactor * 0.1);
if (coverage < 0.01)
{
return;
}
vec3 radialCoords;
radialCoords.x = distFromCenter * 1.425 + 0.55;
radialCoords.y = atan(-rayPos.x, -rayPos.z) * 1.425;
radialCoords.z = distFromDisc * 1.425;
float speed = 0.06;
vec3 coords = radialCoords;
coords.y += iTime * speed;
float structure = fbm(coords * 3.0);
coords.y -= iTime * speed * 2.0;
structure *= fbm(coords * 6.0);
coords.y += iTime * speed * 2.0;
structure *= fbm(coords * 12.0);
vec3 fineCoords = radialCoords + vec3(30.0);
fineCoords.y -= iTime * speed;
float fineDust = fbm(fineCoords * 8.0);
fineDust *= fbm(fineCoords * 20.0 + vec3(0.0, iTime * speed, 0.0));
float spiral = sin(radialCoords.y * 7.0 - distFromCenter * 5.0 + iTime * 0.35) * 0.5 + 0.5;
float filament = smoothstep(0.18, 0.95, structure * 0.72 + spiral * 0.28);
dustColor *= 0.05 + filament * 1.95;
coverage *= fineDust * discMask;
coverage = saturate(coverage * 1200.0 * INV_ITERATIONS);
vec3 orbitalTangent = normalize(vec3(-rayPos.z, 0.0, rayPos.x));
float doppler = saturate(dot(rayDir, orbitalTangent) * 0.5 + 0.5);
vec3 recedingColor = vec3(1.25, 0.44, 0.10);
vec3 approachingColor = vec3(1.7, 1.25, 0.78);
float dopplerCurve = doppler * sqrt(doppler);
dustColor *= mix(recedingColor, approachingColor, dopplerCurve);
dustColor *= 0.78 + doppler * doppler * 0.72;
color = (1.0 - alpha) * max(dustColor, vec3(0.0)) * coverage + color;
alpha = (1.0 - alpha) * coverage + alpha;
}
vec3 toneMap(vec3 color)
{
color *= 230.0;
color += max(color - 0.012, vec3(0.0)) * 0.32;
color = pow(color, vec3(1.42));
color = color / (1.0 + color);
color = pow(color, vec3(1.0 / 1.42));
color = color * color * (3.0 - 2.0 * color);
color = pow(color, vec3(1.2, 1.12, 1.04));
color = saturate(color * 1.01);
return pow(color, vec3(0.7 / 2.2));
}
void mainImage(out vec4 outColor, in vec2 fragCoord)
{
vec2 uv = fragCoord / iResolution.xy;
float aspect = iResolution.x / iResolution.y;
vec2 jitter = vec2(rand(uv + sin(iTime)), rand(uv + 17.0 + sin(iTime))) / iResolution.xy;
vec2 eyeUv = uv + jitter;
vec3 rayDir = normalize(vec3((eyeUv * 2.0 - 1.0) * vec2(aspect, 1.0), 6.0));
vec3 cameraPos = vec3(0.0, 0.0, -10.0);
vec2 mouse = iMouse.xy / max(iResolution.xy, vec2(1.0));
cameraPos.x += (iMouse.z > 0.0 ? mouse.x : 0.35) * 3.0 - 1.5;
rotateCamera(rayDir, cameraPos);
vec3 color = starField(rayDir) * 0.00035;
float alpha = 0.0;
float dither = rand(uv + sin(iTime)) * 2.0;
vec3 rayPos = cameraPos + rayDir * dither * FAR_DISTANCE * INV_ITERATIONS;
for (int i = 0; i < ITERATIONS; i++)
{
warpSpace(rayDir, rayPos);
rayPos += rayDir * FAR_DISTANCE * INV_ITERATIONS;
float singularity = length(rayPos);
if (singularity < 0.42)
{
color *= smoothstep(0.1, 0.42, singularity);
alpha = 1.0;
break;
}
addGasDisc(color, alpha, rayPos, rayDir);
addHaze(color, rayPos, alpha);
}
float ring = abs(sdTorus(rayPos, vec2(1.0, 0.02)));
color += vec3(1.0, 0.83, 0.55) * 0.00008 / (ring * ring + 0.003);
vec2 centeredUv = (uv * 2.0 - 1.0) * vec2(aspect, 1.0);
float screenRadius = length(centeredUv);
float lensRing = abs(screenRadius - 0.19);
float lensBloom = 0.0000018 / (lensRing * lensRing + 0.00045);
lensBloom += 0.0000009 / (screenRadius * screenRadius + 0.08);
color += vec3(1.0, 0.74, 0.36) * lensBloom * (1.0 - alpha * 0.35);
outColor = vec4(toneMap(color * 0.0001), 1.0);
}