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