#ifdef GL_ES
precision mediump float;
#endif
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
#define kPI05 1.5707963267949
#define kPI 3.1415926535898
#define kPI2 6.2831853071796
//
vec3 rotZ(vec3 p, float a) {
vec2 sc = sin(vec2(a, a + kPI05));
return vec3(
p.x * sc.y + p.y * -sc.x,
p.x * sc.x + p.y * sc.y,
p.z
);
}
vec3 lookAt(vec3 o, vec3 t, vec3 u, vec3 d) {
vec3 f = normalize(o - t);
vec3 s = normalize(cross(u, f));
vec3 h = normalize(cross(f, s));
return vec3(
dot(vec3(s.x, h.x, f.x), d),
dot(vec3(s.y, h.y, f.y), d),
dot(vec3(s.z, h.z, f.z), d));
}
// Hash without Sine
https://www.shadertoy.com/view/4djSRW
float hash11(float p) {
p = fract(p * .1031);
p *= p + 33.33;
p *= p + p;
return fract(p);
}
float hash13(vec3 p3) {
p3 = fract(p3 * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
vec2 hash22(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx+33.33);
return fract((p3.xx+p3.yz)*p3.zy);
}
vec3 hash33(vec3 p3) {
p3 = fract(p3 * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yxz+33.33);
return fract((p3.xxy + p3.yxx)*p3.zyx);
}
//
vec3 voro3(vec3 p, vec3 r) {
vec3 ret;
vec3 ip = floor(p);
const int N = 1;
float lmax = 10.0;
vec3 minip;
vec3 mintp;
for(int iz = -N; iz <= N; iz++) {
for(int iy = -N; iy <= N; iy++) {
for(int ix = -N; ix <= N; ix++) {
vec3 tp = ip + vec3(ivec3(ix, iy, iz));
tp += (hash33(tp) - vec3(0.5)) * r;
float l = length(tp - p);
if(l < lmax) {
lmax = l;
minip = ip + vec3(ivec3(ix, iy, iz));
mintp = tp;
}
}
}
}
ret.x = lmax;
ret.z = hash13(minip);
lmax = 10.0;
vec3 minvp;
for(int iz = -N; iz <= N; iz++) {
for(int iy = -N; iy <= N; iy++) {
for(int ix = -N; ix <= N; ix++) {
vec3 tp = minip + vec3(ivec3(ix, iy, iz));
tp += (hash33(tp) - vec3(0.5)) * r;
vec3 vp = tp - mintp;
float l = length(vp);
if(l > 0.0) {
vec3 mp = (tp + mintp) * 0.5;
l = abs(dot(p - mp, vp / l));
if(l < lmax) {
lmax = l;
minvp = vp;
}
}
}
}
}
ret.y = lmax;
return ret;
}
float star(vec2 p) {
float a = atan(p.y, p.x) / kPI2 + 0.5;
a = abs(fract(a * 5.0) * 2.0 - 1.0) * kPI2 / 10.0;
float r = length(p);
vec2 q = cos(vec2(a, a - kPI05)) * r;
float s = kPI / 180.0 * 55.0;
vec2 n = cos(vec2(s, s - kPI05));
return 0.5 - dot(q, n);
}
float flower(vec2 p, float w) {
vec2 tt = vec2(1e2);
for(float i = 0.0; i < 5.0; i+=1.0) {
float a = kPI2 * i / 5.0;
vec2 o = cos(vec2(a, a - kPI05));
float to = length(p - o);
tt = min(tt, vec2(to, abs(to - 1.1756)));
}
return w - (length(p) > 1.0 ? tt.x : tt.y);
}
//
float smin(float a, float b, float k) {
k *= 4.0;
float h = max(k - abs(a - b), 0.0) / k;
return min(a, b) - h * h * k * 0.25;
}
float sphere(vec3 p, vec3 o, float r) {
return length(p - o) - r;
}
vec2 tsphere(vec3 ro, vec3 rd, vec3 sc, float sr, out vec3 ret0, out vec3 ret1) {
vec3 oc = ro - sc;
float a = dot(rd, rd);
float b = 2.0 * dot(rd, oc);
float c = dot(oc, oc) - sr * sr;
float d = b * b - 4.0 * a * c;
if(d < 0.0) return vec2(-1.0);
vec2 t = (vec2(-b) + vec2(-1.0, 1.0) * sqrt(d)) * 0.5 / a;
ret0 = rd * t.x + ro;
ret1 = rd * t.y + ro;
return t;
}
float tplane(vec3 o, vec3 d, vec3 n, vec3 p, out vec3 ret) {
vec3 po = p - o;
float nd = dot(n, d);
float t = dot(n, po) / nd;
if(t < 0.0 || abs(nd) <= 1e-8) return -1.0;
ret = d * t + o;
return t;
}
//
vec3 bg(vec3 p) {
vec3 d = normalize(p);
vec3 c = vec3(0.0, 0.0, 0.02);
vec3 vr = voro3(d * 120.0, vec3(1.0));
float f = 10.0 + abs(sin((vr.z * 24.0 + time) * 2.0)) * 20.0;
vec3 s = mix(vec3(1.0, 0.6, 0.4), vec3(0.4, 0.9, 1.0), fract(vr.z * vr.z * 1e3));
c += pow(vec3(1.0 - sqrt(vr.x)), vec3(10.0)) * f * s;
vec4 hc = mix(vec4(0.1, 0.15, 0.05, 25.0),
vec4(0.0, 0.2, 0.8, 50.0),
smoothstep(-0.03, 0.03, d.y));
c += pow(1.0-abs(d.y), hc.w) * hc.rgb;
c += exp(d.y * -d.y * 3e4) * pow(-d.z, 12.0) * vec3(1.0);
return c;
}
// scene
const float kDz = 4.0;
const float kIntro = 8.0;
const float kSeq = 16.0;
vec2 i2p(vec2 p, float i, inout float y) {
if(i > kIntro) {
float iseq = mod(i - kIntro, kSeq);
if(iseq == 0.0) {
p = vec2(0.0, -1.0);
y *= 2.0;
} else if(iseq > kSeq - 4.0) {
p = vec2(p.x * 0.1, 2.0 - (kSeq - iseq));
}
}
return p;
}
vec2 pos2(float t) {
float i = floor(t);
float f = fract(t);
vec2 xx = vec2(-1.0, 1.0) * (fract(i * 0.5) * 4.0 - 1.0);
float y = 4.0 * f * (1.0 - f);
vec2 o0 = hash22(vec2(i) + vec2(0.0, 0.3456789));
vec2 o1 = hash22(vec2(i + 1.0) + vec2(0.0, 0.3456789));
o0 = o0 * 2.0 - vec2(1.0);
o1 = o1 * 2.0 - vec2(1.0);
vec2 p0 = vec2(xx.x, 0.0) + o0;
vec2 p1 = vec2(xx.y, 0.0) + o1;
p0 = i2p(p0, i, y);
p1 = i2p(p1, i + 1.0, y);
return mix(p0, p1, f) + vec2(0.0, y);
}
float map(vec3 p, vec3 tbif) {
float tb = tbif.x;
float ti = tbif.y;
float tf = tbif.z;
const float N = 16.0;
const float r0 = 0.01;
float d = sphere(p, vec3(pos2(tb), 0.0), r0);
float dt = 0.0;
for(float i = 1.0; i < N; i+=1.0) {
float f = sqrt(i / (N - 1.0));
f = 4.0 * f * (1.0 - f);
dt += mix(0.02, 0.05, f);
vec2 sp = pos2(tb - dt);
float r = 0.1 * f + r0;
float s = mix(0.03, 0.05, f);
d = smin(d, sphere(p, vec3(sp, dt * kDz), r), s);
}
return d;
}
vec3 normal(vec3 p, vec3 t) {
int id;
vec2 e = vec2(1.0, -1.0) * 0.5773;
const float eps = 0.00025;
return normalize( e.xyy * map(p + e.xyy * eps, t) +
e.yyx * map(p + e.yyx * eps, t) +
e.yxy * map(p + e.yxy * eps, t) +
e.xxx * map(p + e.xxx * eps, t) );
}
vec3 fxs(vec3 ro, vec3 rd, float maxt, vec3 tbif) {
float tb = tbif.x;
float ti = tbif.y;
float tf = tbif.z;
vec3 ret = vec3(0.0, 0.0, 0.0);
for(float i = 0.0; i < 4.0; i+=1.0) {
float pti = ti - i;
if(pti < 0.0) break;
float ft = (tb - pti);
vec3 fp = vec3(pos2(pti), ft * kDz);
if(pti < kIntro) maxt = 100.0;
{
vec3 hp;
float ht = tplane(ro, rd, vec3(0.0, 1.0, 0.0), fp, hp);
if(ht >= 0.0 && ht < maxt) {
float r = ft * 1.2;
float t = length(fp - hp);
float f = smoothstep(0.95, 1.0, 1.0 - abs(t - r));
f *= max(0.0, 1.0 - t * t * 1.0);
ret += vec3(1.0, 1.0, 1.0) * f;
}
}
if(pti < kIntro) continue;
float scl = (mod(pti - kIntro, kSeq) == 0.0) ? 4.0 : 1.0;
scl = (pti == kIntro) ? 1.0 : scl;
for(float k = 0.0; k < 2.0; k+=1.0) {
float fd = 1.0 - smoothstep(1.0, 1.5, ft);
float sr = (0.5 * ft * ft + 1e-1) * (1.0 + k * 2.0) * scl;
vec3 sp = fp + vec3(0.0, sr, 0.0);
vec3 shp0, shp1;
vec2 sht = tsphere(ro, rd, sp, sr, shp0, shp1);
for(int j = 0; j < 2; j++) {
float st = (j == 0) ? sht.x : sht.y;
if(st < 0.0 || st > maxt) continue;
vec3 lp = rd * st + ro - sp;
float a = atan(lp.z, lp.x) + pti * 0.7 + k * 0.6;
float r = acos(clamp(-lp.y / sr, -1.0, 1.0)) / kPI;
r *= max(1.0, sr * 5.0 / scl);
vec2 uv = cos(vec2(a, a - kPI05)) * r;
// ret += vec3(fract(length(uv)));
float tx = flower(uv, 0.04);
ret += vec3(4.0, 3.0, 2.0) * smoothstep(-0.02, 0.04, tx) * fd;
}
}
float strrng = fract(sin(pti + 1.7654321));
for(float k = 0.0; k < 20.0; k+= 1.0) {
strrng = fract(strrng * (1.23456 + strrng) * 100.0);
float rnd = strrng;
float a = (k + pti) * 2.4 + rnd;
vec3 pp = fp;
pp.xz += cos(vec2(a, a - kPI05)) * ft * (0.4 + rnd * 0.8) * scl;
pp.y += ft * (0.9 + rnd * 0.5 - ft) * 2.0 * scl;
vec3 hp;
float ht = tplane(ro, rd, vec3(0.0, 0.0, -1.0), pp, hp);
if(ht >= 0.0 && ht < maxt) {
vec2 uv = (hp.xy - pp.xy) * 12.0 / scl;
uv = rotZ(uv.xyy, k * 2.4).xy;
float tx = star(uv);
float fd = 1.0 - smoothstep(1.0, 1.5, ft);
ret += vec3(1.5, 1.0, 0.6) * fd * smoothstep(-0.1, 0.1, tx);
}
}
}
return ret;
}
void main() {
vec3 t;
t.x = time * 120.0 / 60.0;
t.y = floor(t.x);
t.z = fract(t.x);
vec3 color = vec3(0.0);
vec2 sc = (gl_FragCoord.xy * 2.0 - resolution.xy) / min(resolution.x, resolution.y);
vec3 ro = vec3(0.0, 0.0, 10.0);
vec3 rd = normalize(vec3(sc.xy, -4.0));
ro.xy += vec2(0.0, 0.4 + sin(time * 1.3) * 0.03) + sin(vec2(time) * vec2(0.7, 1.15)) * 0.04;
vec3 lp = vec3(pos2(t.x - 0.6) * vec2(0.02, 0.002), sin(time * 0.2) * 0.05);
rd = lookAt(ro, lp, vec3(0.0, 1.0, 0.0), rd);
color = bg(rd);
float td = 0.0;
float blm = 0.0;
for(int i = 0; i < 64; i++) {
vec3 rp = rd * td + ro;
float d = map(rp, t);
if(d < 1e-2) {
vec3 nv = normal(rp, t);
color = mix(vec3(0.4, 0.4, 0.55), vec3(0.8), (nv.y * 0.5 + 0.5));
color += vec3(0.2, 0.3, 0.0) * (1.0 - abs(nv.y));
break;
}
blm += pow(max(0.0, 1.0 - d * 8.0), 10.0);
td += d;
}
color += vec3(0.1, 0.2, 0.2) * blm;
if(t.y < kIntro) {
color = vec3(0.0);
} else {
color += max(0.0, 1.0 - (t.x - kIntro) * 2.0);
}
color += fxs(ro, rd, td, t);
gl_FragColor = vec4(pow(color, vec3(1.0/2.2)), 1.0);
}