precision highp float; #define OUT_COLOR outColor out vec4 outColor; uniform vec2 resolution; uniform float time; #define F4 0.309016994374947451 float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } float permute(float x) { return mod289(((x * 34.0) + 1.0) * x); } vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); } vec4 permute(vec4 x) { return mod289(((x * 34.0) + 1.0) * x); } float taylorInvSqrt(float r) { return 1.79284291400159 - 0.85373472095314 * r; } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } float snoise2D(vec2 v) { const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) -0.577350269189626, // -1.0 + 2.0 * C.x 0.024390243902439); // 1.0 / 41.0 // First corner vec2 i = floor(v + dot(v, C.yy)); vec2 x0 = v - i + dot(i, C.xx); // Other corners vec2 i1; //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 //i1.y = 1.0 - i1.x; i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); // x0 = x0 - 0.0 + 0.0 * C.xx ; // x1 = x0 - i1 + 1.0 * C.xx ; // x2 = x0 - 1.0 + 2.0 * C.xx ; vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1; // Permutations i = mod289(i); // Avoid truncation effects in permutation vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); m = m * m; m = m * m; // Gradients: 41 points uniformly over a line, mapped onto a diamond. // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) vec3 x = 2.0 * fract(p * C.www) - 1.0; vec3 h = abs(x) - 0.5; vec3 ox = floor(x + 0.5); vec3 a0 = x - ox; // Normalise gradients implicitly by scaling m // Approximation of: m *= inversesqrt( a0*a0 + h*h ); m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); // Compute final noise value at P vec3 g; g.x = a0.x * x0.x + h.x * x0.y; g.yz = a0.yz * x12.xz + h.yz * x12.yw; return 130.0 * dot(m, g); } float snoise3D(vec3 v) { const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); // First corner vec3 i = floor(v + dot(v, C.yyy)); vec3 x0 = v - i + dot(i, C.xxx); // Other corners vec3 g = step(x0.yzx, x0.xyz); vec3 l = 1.0 - g; vec3 i1 = min(g.xyz, l.zxy); vec3 i2 = max(g.xyz, l.zxy); // x0 = x0 - 0.0 + 0.0 * C.xxx; // x1 = x0 - i1 + 1.0 * C.xxx; // x2 = x0 - i2 + 2.0 * C.xxx; // x3 = x0 - 1.0 + 3.0 * C.xxx; vec3 x1 = x0 - i1 + C.xxx; vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations i = mod289(i); vec4 p = permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + i.x + vec4(0.0, i1.x, i2.x, 1.0)); // Gradients: 7x7 points over a square, mapped onto an octahedron. // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) float n_ = 0.142857142857; // 1.0/7.0 vec3 ns = n_ * D.wyz - D.xzx; vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) vec4 x_ = floor(j * ns.z); vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) vec4 x = x_ * ns.x + ns.yyyy; vec4 y = y_ * ns.x + ns.yyyy; vec4 h = 1.0 - abs(x) - abs(y); vec4 b0 = vec4(x.xy, y.xy); vec4 b1 = vec4(x.zw, y.zw); //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; vec4 s0 = floor(b0) * 2.0 + 1.0; vec4 s1 = floor(b1) * 2.0 + 1.0; vec4 sh = -step(h, vec4(0.0)); vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; vec3 p0 = vec3(a0.xy, h.x); vec3 p1 = vec3(a0.zw, h.y); vec3 p2 = vec3(a1.xy, h.z); vec3 p3 = vec3(a1.zw, h.w); //Normalise gradients vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); m = m * m; return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); } vec3 hsv(float h, float s, float v) { vec4 t = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(vec3(h) + t.xyz) * 6.0 - vec3(t.w)); return v * mix(vec3(t.x), clamp(p - vec3(t.x), 0.0, 1.0), s); } mat2 rotate2D(float r) { return mat2(cos(r), sin(r), -sin(r), cos(r)); } mat3 rotate3D(float angle, vec3 axis) { vec3 a = normalize(axis); float s = sin(angle); float c = cos(angle); float r = 1.0 - c; return mat3(a.x * a.x * r + c, a.y * a.x * r + a.z * s, a.z * a.x * r - a.y * s, a.x * a.y * r - a.z * s, a.y * a.y * r + c, a.z * a.y * r + a.x * s, a.x * a.z * r + a.y * s, a.y * a.z * r - a.x * s, a.z * a.z * r + c); } const float PI = 3.141592653589793; const float PI2 = PI * 2.0; const float TAU = PI * 0.5; // ===================== // Subtract: Obj1 - Obj2 float opS(float d1, float d2) { return max(d1, -d2); } // Union: Obj1 + Obj2 float opU(float d1, float d2) { return min(d1, d2); } // Intersection: Obj1 & Obj2 float opI(float d1, float d2) { return max(d1, d2); } float sdSphere(vec3 p, float s) { return length(p) - s; } // t: {radius, tube radius} float sdTorus(vec3 p, vec2 t) { vec2 q = vec2(length(p.xz) - t.x, p.y); return length(q) - t.y; } float length_toPowNegative8(vec2 p) { p = p * p; p = p * p; p = p * p; return pow(p.x + p.y, 1.0 / 8.0); } float sdTorus82(vec3 p, vec2 t) { vec2 q = vec2(length(p.xz) - t.x, p.y); return length_toPowNegative8(q) - t.y; } float sdTorus88(vec3 p, vec2 t) { vec2 q = vec2(length_toPowNegative8(p.xz) - t.x, p.y); return length_toPowNegative8(q) - t.y; } float sd2Circle(vec2 p, float r) { return length(p) - r; } float sd2Circle(vec2 p, vec2 c, float r) { return length(c - p) - r; } float sd2Arc(vec2 p, vec2 o, float r1, float r2, float t) { if (t > 1. - 1e-3) return opS(sd2Circle(p, o, r1), sd2Circle(p, o, r2)); float a = t * 2. * PI; float s = sin(a); float c = -cos(a); mat2 m = mat2(c, s, -s, c); float arc1 = opS(opS(sd2Circle(p, o, r1), sd2Circle(p, o, r2)), p.x); float arc2 = opS(opS(sd2Circle(p, o, r1), sd2Circle(p, o, r2)), (p * m).x); return mix(opI(arc1, arc2), opU(arc1, arc2), step(.5, t)); } float sd2Square(vec2 p, vec2 pos, float h, float angle) { vec2 l = p - pos; l *= rotate2D(angle); vec2 d = abs(l) - h; float outside = length(max(d, 0.)); float inside = min(max(d.x, d.y), 0.); return outside + inside; } float sd2Line(in vec2 p, in vec2 dir, in float s) { p -= .5; vec2 perpendicular = vec2(-dir.y, dir.x); if (dot(p, dir) > 0.) { return abs(dot(p, perpendicular)) - s; } else { return 1.; } } // symU and rotU apply to vectors that range from 0 to 1 void symU(inout vec2 u) { u.x = 1. - u.x; } void rotU(inout vec2 u) { u.xy = vec2(u.y, 1. - u.x); } // symV and rotV apply to unit vectors that range from -1 to 1 void symV(inout vec2 v) { v.x = -v.x; } void rotV(inout vec2 v) { v.xy = vec2(v.y, -v.x); } float sd2Hilbert(in vec2 p, float width, float mTime) { const float iter = 7.; float t = 0.0; vec2 U = p; vec2 I = vec2(1, 0); vec2 J = vec2(0, 1); vec2 L = -I; vec2 R; vec2 qU; for (float i = 0.; i < iter; i++) { qU = step(.5, U); // select quadrant bvec2 q = bvec2(qU); // convert to boolean float h = 1. / pow(4., i + 1.); t += h * (q.x ? (2. + qU.y) : (1. - qU.y)); U = 2. * U - qU; // go to new quadrant // qU: q: // 0,1 | 1,1 f,t | t,t // ------|----- ----------- // 0,0 | 1,0 f,f | t,f // L: R: // L | -J -J | I // -----|----- ---------- // J | -I I | J // node left segment L = q.x ? (q.y ? -J : -I) : (q.y ? L : J); R = (q.x == q.y) ? I : (q.y ? -J : J); // node right segment if (q.x) { // sym symU(U); symV(L); symV(R); vec2 tmp = L; L = R; R = tmp; } if (q.y) { // rot+sym rotU(U); symU(U); rotV(L); symV(L); rotV(R); symV(R); } } float s = width * pow(2., iter); s *= mix(.5, 2.5, snoise2D(vec2(t, 0.) * pow(2., iter + 1.) + mTime * .4) * .5 + .5); return opU(sd2Line(U, L, s), sd2Line(U, R, s)); } mat4 rotate_xz(float x) { return mat4(cos(x), 0.0, -sin(x), 0.0, 0.0, 1.0, 0.0, 0.0, sin(x), 0.0, cos(x), 0.0, 0.0, 0.0, 0.0, 1.0); } mat4 rotate_xy(float x) { return mat4(cos(x), -sin(x), 0.0, 0.0, sin(x), cos(x), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); } vec3 rotate(const vec3 p, mat4 m) { return vec3(m * vec4(p, 1.0)); } float rand(vec2 seed) { return fract(sin(dot(seed.xy, vec2(12.9898, 78.233))) * 43758.5453); } vec2 rand22(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); } float rand(inout vec2 v, inout float state) { v = (1. / 4320.) * v + vec2(0.25, 0.); state = fract(dot(v * v, vec2(3571))); return fract(state * state * (3571. * 2.)); } vec3 randomSpherePoint(vec3 rand) { float ang1 = (rand.x + 1.0) * PI; // [-1..1) -> [0..2*PI) float u = rand.y; // [-1..1), cos and acos(2v-1) cancel each other out, so we arrive at [-1..1) float u2 = u * u; float sqrt1MinusU2 = sqrt(1.0 - u2); float x = sqrt1MinusU2 * cos(ang1); float y = sqrt1MinusU2 * sin(ang1); float z = u; return vec3(x, y, z); } vec3 rand_in_unit_sphere(vec2 co) { float s = co.x + co.y; vec3 sp = randomSpherePoint(vec3(rand(co, s), rand(co, s), rand(co, s))); float r = pow(rand(co, s), 1. / 3.); return sp * r; } float saturate(float x) { return clamp(x, 0., 1.); } float unlerp(float a, float b, float x) { return saturate((x - a) / (b - a)); } float ease_in(float from, float to, float t) { return mix(from, to, pow(t, 4.)); } float ease_out(float from, float to, float t) { return mix(to, from, pow(1. - t, 4.)); } float ease_in_out(float from, float to, float t) { return mix(from, to, mix(4. * t * t * t, 1. - pow(-2. * t + 2., 3.) * .5, step(.5, t))); } //==== TIMELINE int timelineStep = 0; float mTime; float phaseT; #define NEXT(phase) phase + 1 const int P_START = 0; const float P_START_T = 0.; const float P_START_E = P_START_T + 2.; const int P_CIRC = NEXT(P_START); const float P_CIRC_T = P_START_E; const float P_CIRC_E = P_CIRC_T + 1.; const int P_BALL = NEXT(P_CIRC); const float P_BALL_T = P_CIRC_E; const float P_BALL_E = P_BALL_T + 60.; const int P_GLITCH = NEXT(P_BALL); const float P_GLITCH_T = P_BALL_E; const float P_GLITCH_E = P_GLITCH_T + 25.; const int P_END = NEXT(P_GLITCH); const float P_END_T = P_GLITCH_E; const float P_END_E = P_END_T + 2.; const float END_T = P_END_E; #define T_START_PROGRESS ease_in_out(0., 1., unlerp(.0, .9, phaseT)) #define T_START_FILL ease_in(1., 0., unlerp(.9, 1., phaseT)) #define T_CIRC_SIZE ease_in(1., 0., unlerp(.3, 1., phaseT)) #define T_CIRC_ROTATE sqrt(1. - pow(phaseT - 1., 2.)) #define T_BALL_SIZE ease_out(.8, 1., unlerp(0., .02, phaseT)) #define T_BALL_FLOOR_FADE ease_in(0., 1., saturate(phaseT / .1)) #define T_BALL_FLOOR_TINT unlerp(.7, .85, phaseT) #define T_BALL_LIGHT_ROTATE smoothstep(0., .2, phaseT) #define T_BALL_LIGHT_FADE ease_out(1., .2, unlerp(.02, .2, phaseT)) #define T_BALL_SQUARES_FADE smoothstep(.1, .2, phaseT) #define T_BALL_CURVE_FADE unlerp(.2, .4, phaseT) #define T_BALL_ROTATE ease_in_out(0., 1., unlerp(.5, 1., phaseT)) #define T_BALL_ROTATE_UV clamp(phaseT, 0., .75) #define T_GLITCH_LIGHT_ROTATE (P_BALL_E + unlerp(.0, .025, phaseT) * .5) #define T_GLITCH_BALL_JITTER (1. - abs(ease_out(-1., 1., saturate(phaseT / .05)))) #define T_GLITCH_MODEL mix( mix(.0, 1., unlerp(.25,.6,phaseT)), mix(.5, 1., unlerp(.25,.6,phaseT)), rand(vec2(phaseT)) ) #define T_GLITCH_RING_TWIST ease_in(0., 1., unlerp(.55, .6, phaseT)) #define T_GLITCH_RING_ROTATE clamp(phaseT, .0, .585) #define T_GLITCH_UNLIT step(.6, phaseT) #define T_GLITCH_BLOCK step(.6, phaseT) #define T_GLITCH_PROB ease_in(.9, .6, unlerp(.65, 1., phaseT)) #define T_END_SHUTTER ease_out(1., 0., unlerp(.4, .6, phaseT)) #define SET_IF_PHASE(phase, start, end) if(mTime < end){ timelineStep = phase; phaseT = unlerp(start, end, mTime); } mat4 transform; void setup() { mTime = mod(time, END_T); SET_IF_PHASE(P_START, P_START_T, P_START_E) else SET_IF_PHASE(P_CIRC, P_CIRC_T, P_CIRC_E) else SET_IF_PHASE(P_BALL, P_BALL_T, P_BALL_E) else SET_IF_PHASE(P_GLITCH, P_GLITCH_T, P_GLITCH_E) else SET_IF_PHASE(P_END, P_END_T, P_END_E); transform = rotate_xz(0.); if (timelineStep == P_BALL) { transform = rotate_xy(PI * T_BALL_ROTATE); } } //====================== float sdDist(vec3 position) { if (timelineStep == P_BALL) { return sdSphere(position, 1.65 * T_BALL_SIZE); } else if (timelineStep == P_GLITCH) { float m1 = sdSphere(position + .5 * rand_in_unit_sphere(vec2(mTime)) * T_GLITCH_BALL_JITTER, 1.65); mat3 r1 = rotate3D(TAU + T_GLITCH_RING_ROTATE * 100., vec3(.9, .5, .1)); mat3 r2 = rotate3D(T_GLITCH_RING_ROTATE * 30., vec3(1.)); mat4 r3 = rotate_xz(TAU * .5) * rotate_xy(TAU) * rotate_xz(TAU + TAU * sin(position.y) * T_GLITCH_RING_TWIST); float m2 = opU(opU(sdTorus(position * r1, vec2(.2, .05)), sdTorus82(position * r2, vec2(1.6, .1))), sdTorus88(rotate(position, r3), vec2(.6, .2))); return mix(m1, m2, step(.5, T_GLITCH_MODEL) * step(T_GLITCH_MODEL, .995)); } else { return 0.; } } vec3 sdNorm(vec3 pos) { vec2 e = vec2(1.0, -1.0) * 0.5773 * 0.0001; return normalize(e.xyy * sdDist(pos + e.xyy) + e.yyx * sdDist(pos + e.yyx) + e.yxy * sdDist(pos + e.yxy) + e.xxx * sdDist(pos + e.xxx)); } // true = reflect bool lighting3d(in vec3 pos, in int i, out vec2 uv, out vec3 norm) { if (timelineStep == P_BALL) { vec3 v = normalize(pos); const float UVSCALE = 10.; uv = vec2(atan(v.x, -v.z), v.y) * UVSCALE; if (timelineStep == P_BALL) uv *= rotate2D(2. * PI2 * T_BALL_ROTATE_UV); uv = uv - mTime * sign(uv); norm = normalize(pos); vec3 tang = normalize(cross(norm, vec3(0., 1., 0.))); norm = rotate(norm, inverse(transform)); tang = rotate(tang, inverse(transform)); float randX = rand(vec2(round(uv.x), floor(uv.y))); float randY = rand(vec2(floor(uv.x), round(uv.y)) + vec2(29.273, 1.378)); vec2 sideOn = step(.25, vec2(randX, randY)); uv = fract(uv); const float W = .15; vec4 corners = vec4(step(uv.x + uv.y, 1.), step(1., uv.x + uv.y), step(uv.x - uv.y, 0.), step(0., uv.x - uv.y)); vec4 sideFill = clamp(vec4(corners.xxyy * corners.zwwz + (1. - sideOn.yxyx)), vec4(0.), vec4(1.)); vec4 sides = vec4(step(uv, vec2(W)), step(1. - W, uv)) * sideFill * sideOn.xyxy; if (sides.x + sides.y + sides.z + sides.w > 0.) { vec3 ex1 = normalize(vec3(1., 0., 1.)); vec3 ex2 = normalize(vec3(-1., 0., 1.)); vec3 ey1 = normalize(vec3(0., -1., 1.)); vec3 ey2 = normalize(vec3(0., 1., 1.)); vec3 ez = vec3(0., 0., 1.); vec4 uuvv = vec4(1. - uv / W, (uv - 1. + W) / W); float tx = dot(sides.xz, uuvv.xz); vec3 Nx = (sides.x + sides.z) * mix(ez, mix(ex1, ex2, sides.x), tx * tx); float ty = dot(sides.yw, uuvv.yw); vec3 Ny = (sides.y + sides.w) * mix(ez, mix(ey1, ey2, sides.y), ty * ty); vec3 bitan = normalize(cross(norm, tang)); mat3 m = mat3(tang, bitan, norm); norm = m * normalize(Nx + Ny); } norm = normalize(norm + .2 * rand_in_unit_sphere(uv.xy)); return true; } else { norm = sdNorm(pos); norm = rotate(norm, inverse(transform)); return !(timelineStep == P_GLITCH && T_GLITCH_RING_TWIST > .99); } } const vec3 COLOR_GRN = vec3(0.2, .3, 0.); const vec3 COLOR_RED = vec3(.3, 0.0, 0.1); const vec3 COLOR_BLU = vec3(0., 0.2, 0.4); bool lighting2d(in vec2 p, in int i, out vec3 color) { if (timelineStep == P_CIRC) { if (i == 0) color += vec3(.5); else if (i == 1) color += COLOR_GRN; else if (i == 2) color += COLOR_RED; else if (i == 3) color += COLOR_BLU; } else if (timelineStep == P_END) { color += vec3(fract(p.y * 64. + mTime * vec3(.45, .89, .1))) * step(abs(p.y), T_END_SHUTTER); } else { color = vec3(1.); } return false; } vec3 missColor(vec3 pos, vec3 dir) { const vec3 colorD = vec3(0.02, 0.02, 0.04); const vec3 colorL = vec3(1.0); vec3 color; float t2 = (pos.y - 500.0) / dir.y; if (t2 > 0.0) { if (timelineStep == P_BALL) { vec3 p = pos + t2 * dir * .99; vec2 uv = p.xz / vec2(300. * sign(p.x), 700.); float wave = sin(uv.y + uv.x - mTime * 10.) * .5 + .2; float fade = exp(-abs(p.z) / mix(5., 3000., T_BALL_FLOOR_FADE)); color = mix(colorD, colorL, wave * fade); color *= hsv(fract(uv.y / 20. + mTime * .25), T_BALL_FLOOR_TINT, 1.); } else if (timelineStep == P_GLITCH) { vec3 p = pos + t2 * dir * .99; vec2 uv = p.xz / vec2(300. * sign(p.x), 700.); float wave = sin(uv.y + uv.x - mTime * 10.) * .5 + .2; float fade = exp(-abs(p.z) / 3000.); float w = mix(wave, step(0., wave), T_GLITCH_UNLIT); color = mix(colorD, colorL, w * fade); } } else if (timelineStep == P_BALL || timelineStep == P_GLITCH) { vec2 r = resolution; vec2 pix = (dir.xy / dir.z + vec2(.5 * r.x / r.y, .5)) * r.y; vec2 uvBg = (pix - r) / max(r.x, r.y); vec2 uv = uvBg * step(pos.z, -4.99); vec2 p = fract(uv); vec2 num = vec2(10., 10.); for (int i = 0; i < 100; i++) { float x = float(i) / num.x; float t = mTime * .5; float y = mod(float(i) - t, num.y); float y_id = y + t; vec2 seed = vec2(x, y_id); float s = float(i); vec2 pos = (vec2(x, y) + rand22(vec2(x, y_id) * .1)) * (1. / num.x) + vec2(0., .5); float r1 = rand(seed, s); float r2 = .5 - rand(seed, s); float g1 = sign(r2) * 10. * step(abs(r2), .1) * step(.5, float(timelineStep - P_BALL)); float g2 = sign(r2) * 2. * sin(mTime * .5) * step(.2, abs(r2)) * step(.5, float(timelineStep - P_BALL)); float d = sd2Square(p, pos, mix(.01, .02, r1), mTime * r2 + g1 + g2); color += step(d, 0.) * mix(vec3(.1) * T_BALL_SQUARES_FADE, vec3(.5), step(.5, float(timelineStep - P_BALL))); } if (timelineStep == P_BALL) { vec2 uvHb = (pix.xy * 2. - r) / min(r.x, r.y) * step(pos.z, -4.99); uvHb *= rotate2D(.05 * mTime); uvHb = uvHb * (.4 / max(r.x, r.y) * min(r.x, r.y)) + .5; float hb = sd2Hilbert(uvHb, 1. / max(r.x, r.y), mTime); color += step(hb, 0.) * vec3(.1) * T_BALL_CURVE_FADE; color += mix(colorD, colorL * .5, dir.y * dir.y); } else if (timelineStep == P_GLITCH) { color += mix(colorD, colorL * .5, dir.y * dir.y); color = mix(color, fract(dir * 4.).xyy * .7, T_GLITCH_UNLIT); } } else { color = mix(colorD, colorL, dir.y * dir.y); } return color; } // ============== float intersect(in vec3 rO, in vec3 rD, in float maxT, out vec3 tRay) { float dist, t; float res = -1.0; t = 0.01; for (int i = 0; i < 64; i++) { if (t > maxT) break; vec3 p = rO + t * rD; p = rotate(p, transform); dist = sdDist(p); if (dist < 0.0001) { tRay = p; res = t; break; } t += dist; } return res; } float intersect2d(vec2 p, int i) { if (timelineStep == P_START) { if (i == 0) { float t = T_START_PROGRESS; float r = T_START_FILL; return sd2Arc(p, vec2(0.), .2, .18 * r, saturate(t)); } } else if (timelineStep == P_CIRC) { if (i == 0) { float t = T_CIRC_SIZE; return sd2Circle(p, .2 * t); } else if (i < 4) { float t = T_CIRC_ROTATE; float a = PI / 1.5 * float(i) + 2. * PI * t; float x = sin(a); float y = cos(a); return sd2Circle(p, .4 * t * vec2(x, y * T_CIRC_SIZE), .2); } } else if (timelineStep == P_END) { if (i == 0) return sd2Circle(p, .35); else if (i == 1) return -1.; } return 0.; } vec3 lights(in vec3 pos, in vec3 dir) { vec3 c = vec3(0.); if (timelineStep == P_BALL) { vec3 _a; vec3 up = T_BALL_LIGHT_ROTATE * vec3(0., 1.2, 0.); vec3 l1dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 1. + 2. * mTime * T_BALL_LIGHT_ROTATE)) + up - pos; vec3 l2dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 2. + 2. * mTime * T_BALL_LIGHT_ROTATE)) + up - pos; vec3 l3dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 3. + 2. * mTime * T_BALL_LIGHT_ROTATE)) + up - pos; float v1 = step(intersect(pos, l1dir, 5., _a), 0.); float v2 = step(intersect(pos, l2dir, 5., _a), 0.); float v3 = step(intersect(pos, l3dir, 5., _a), 0.); float l1 = unlerp(.5, 1., dot(dir, normalize(l1dir))) * v1; float l2 = unlerp(.5, 1., dot(dir, normalize(l2dir))) * v2; float l3 = unlerp(.5, 1., dot(dir, normalize(l3dir))) * v3; c += l1 * COLOR_RED + l2 * COLOR_BLU + l3 * COLOR_GRN; vec3 scale = vec3(1., 10., 1.); l1 = saturate(dot(dir, normalize(scale * l1dir))) * v1; l2 = saturate(dot(dir, normalize(scale * l2dir))) * v2; l3 = saturate(dot(dir, normalize(scale * l3dir))) * v3; c += l1 * COLOR_RED + l2 * COLOR_BLU + l3 * COLOR_GRN; c *= 3. * T_BALL_LIGHT_FADE; } else if (timelineStep == P_GLITCH) { vec3 up = vec3(0., 1.2, 0.); vec3 l1dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 1. + 2. * T_GLITCH_LIGHT_ROTATE)) + up - pos; vec3 l2dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 2. + 2. * T_GLITCH_LIGHT_ROTATE)) + up - pos; vec3 l3dir = rotate(vec3(3., 0., 0.), rotate_xz(PI / 6. + PI / 1.5 * 3. + 2. * T_GLITCH_LIGHT_ROTATE)) + up - pos; vec3 scale = vec3(1., 10., 1.); float l1 = saturate(dot(dir, normalize(scale * l1dir))); float l2 = saturate(dot(dir, normalize(scale * l2dir))); float l3 = saturate(dot(dir, normalize(scale * l3dir))); c += l1 * COLOR_RED + l2 * COLOR_BLU + l3 * COLOR_GRN; c *= 2.; } return c; } vec3 trace(vec2 p, vec3 _pos, vec3 _dir) { vec3 color = vec3(0.0); vec3 w = vec3(1.0); vec3 pos = _pos, dir = _dir; bool trace3d = timelineStep == P_BALL || timelineStep == P_GLITCH; for (int i = 0; i < 4; i++) { if (trace3d) { vec3 view; float t = intersect(pos, dir, 50.0, view); if (t > 0.0) { vec3 inter = pos + t * dir * .99; pos = inter; vec3 nor; vec2 uv; bool refl = lighting3d(view, 0, uv, nor); color += lights(pos, nor); if (!refl) { return w * color; } dir = reflect(dir, nor); w *= vec3(.9, .88, .85); } else { color += missColor(pos, dir); return w * color; } } else { for (int j = 0; j < 20; j++) { float t = intersect2d(p, j); if (t < 0. && lighting2d(p, j, color)) { break; } } return w * color; } } return vec3(0.); } vec3 jitter_cam(vec2 pix, vec3 dir) { vec2 block = floor(pix / 32.); float line = floor(pix.y / 64.); if (timelineStep == P_GLITCH) { float s = floor(mTime / .1); float r1 = snoise3D(vec3(block * 25., s)) * saturate(1.25 - length(dir.xy)); float r2 = rand(vec2(floor(mTime / .2), line)); if (r2 > .9) { dir.xy += .02 * rand(vec2(line)) * T_GLITCH_BLOCK; } else if (r1 == .7) { dir.xy += .05 * rand22(block.yx) * T_GLITCH_BLOCK; } } return normalize(dir); } void glitch_color(vec2 pix, inout vec3 color) { vec2 block = floor(pix / 32.); if (timelineStep == P_GLITCH) { float s = floor(mTime / .01); float r = snoise3D(vec3(block * vec2(.05, 2.), s)); if (r > T_GLITCH_PROB) color *= vec3(1., 1., 1.) - vec3(1., 0., 1.) * T_GLITCH_BLOCK; else if (rand(vec2(floor(mTime / .5))) > .9) color = color.rrr; } } void main() { vec2 r = resolution, p = gl_FragCoord.xy / r.y - vec2(.5 * r.x / r.y, .5); setup(); vec3 vdir = normalize(vec3(p, 1.0)); vec3 pcam = vec3(0.0, 0.0, -5.0); // glitch vdir = jitter_cam(gl_FragCoord.xy, vdir); vec3 color = trace(p, pcam, vdir); glitch_color(gl_FragCoord.xy, color); OUT_COLOR = vec4(color, 1); }