
/*{ "CREDIT": "CC0", "DESCRIPTION": "A segmented industrial worm machine picking its way through a derelict maze inside a dead machine. The maze is a lattice of junction chambers joined by square ducts, several lanes wide and up to three floors deep: the route turns left and right and climbs and drops through shafts, and every other duct is opened or sealed by a hash, which is what makes the side passages, loops and dead ends. Many ducts have a bulkhead halfway along with a small bolted PORT, and the worm compresses exactly as much as the hole demands to squeeze through, anchor FINS folding as it goes. The worm is built rather than grown: faceted plate segments with real gaps, an exposed drive shaft bridging them, a dorsal rail, radii that step down per segment, a machined nose plate with a stuttering headlamp, and a faceted stinger spike for a tail with a red beacon ring at its root. The place is filthy -- rust streaks, soot in the corners, dust on every up-facing surface, burnt-out chambers, dead indicator panels and a few sick survivors, corroded boards and decades-old wiring -- all of it under GRIME. Four passes: route state, scene, bloom, grade. Cameras: follow (rides the route behind the worm), head, overhead (the maze from above with the roof cut away). ARMOR: brushed steel, black anodized, copper, bone ceramic, hazard yellow, chrome, oxide red, carbon weave. STYLE: service light, cold diagnostic, amber fault, thermal, phosphor, ultraviolet, borescope, ink plate. Try LANES and FLOORS at maximum with BRANCH high for a labyrinth.", "CATEGORIES": ["Generator", "3D", "Raymarch"], "ISFVSN": "2", "INPUTS": [ { "NAME": "uSpeed", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 3.0 }, { "NAME": "uLength", "TYPE": "float", "DEFAULT": 7.00, "MIN": 2.0, "MAX": 14.0 }, { "NAME": "uGirth", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.50, "MAX": 1.40 }, { "NAME": "uWeave", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 2.0 }, { "NAME": "uSegLen", "TYPE": "float", "DEFAULT": 0.42, "MIN": 0.18, "MAX": 0.90 }, { "NAME": "uFins", "TYPE": "float", "DEFAULT": 0.60, "MIN": 0.0, "MAX": 1.00 }, { "NAME": "uArmor", "TYPE": "long", "DEFAULT": 0, "VALUES": [0,1,2,3,4,5,6,7], "LABELS": ["brushed steel","black anodized","copper","bone ceramic","hazard yellow","chrome","oxide red","carbon weave"] }, { "NAME": "uCell", "TYPE": "float", "DEFAULT": 4.50, "MIN": 3.60, "MAX": 7.0 }, { "NAME": "uLanes", "TYPE": "long", "DEFAULT": 2, "VALUES": [1,2,3], "LABELS": ["3 wide","5 wide","7 wide"] }, { "NAME": "uFloors", "TYPE": "long", "DEFAULT": 2, "VALUES": [1,2,3], "LABELS": ["1 floor","2 floors","3 floors"] }, { "NAME": "uBranch", "TYPE": "float", "DEFAULT": 0.55, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "uBore", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.80, "MAX": 1.30 }, { "NAME": "uPort", "TYPE": "float", "DEFAULT": 0.45, "MIN": 0.25, "MAX": 0.95 }, { "NAME": "uClutter", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 1.50 }, { "NAME": "uWires", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 1.50 }, { "NAME": "uLamp", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 3.0 }, { "NAME": "uCone", "TYPE": "float", "DEFAULT": 0.55, "MIN": 0.15, "MAX": 1.00 }, { "NAME": "uLeds", "TYPE": "float", "DEFAULT": 0.70, "MIN": 0.0, "MAX": 2.50 }, { "NAME": "uHaze", "TYPE": "float", "DEFAULT": 0.85, "MIN": 0.0, "MAX": 1.50 }, { "NAME": "uGrime", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.0, "MAX": 1.50 }, { "NAME": "uSpark", "TYPE": "float", "DEFAULT": 0.40, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "uView", "TYPE": "long", "DEFAULT": 0, "VALUES": [0,1,2], "LABELS": ["follow","head","overhead"] }, { "NAME": "uDist", "TYPE": "float", "DEFAULT": 1.70, "MIN": 0.40, "MAX": 5.0 }, { "NAME": "uFov", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.60, "MAX": 1.80 }, { "NAME": "uStyle", "TYPE": "long", "DEFAULT": 0, "VALUES": [0,1,2,3,4,5,6,7], "LABELS": ["service light","cold diagnostic","amber fault","thermal","phosphor","ultraviolet","borescope","ink plate"] }, { "NAME": "uGain", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.20, "MAX": 3.0 }, { "NAME": "uGamma", "TYPE": "float", "DEFAULT": 1.00, "MIN": 0.60, "MAX": 1.60 }, { "NAME": "uBloom", "TYPE": "float", "DEFAULT": 0.60, "MIN": 0.0, "MAX": 2.0 }, { "NAME": "uVign", "TYPE": "float", "DEFAULT": 0.50, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "uFilm", "TYPE": "float", "DEFAULT": 0.50, "MIN": 0.0, "MAX": 1.0 } ], "PASSES": [ { "TARGET": "st", "FLOAT": true }, { "TARGET": "sc", "FLOAT": true }, { "TARGET": "bl", "FLOAT": true }, { } ] }*/ // =========================================================================== // A robotic worm finding its way through a maze of machine ducting. // // THE MAZE is a lattice of chambers, one per node (i*C, k*C, s*C), joined by // square corridors. Every corridor carries a bulkhead halfway along with a // small bolted port in it. Nodes live in a band a few lanes wide and a few // floors deep and run forever along z. // // THE ROUTE is chosen before the maze is. Stage s of the route starts at node // (Lx(s), Ly(s), s), shifts sideways to lane Lx(s+1), climbs or drops to floor // Ly(s+1), then steps forward to row s+1. The lanes are smoothed hashes of s // -- absolute, not accumulated -- so "is this corridor on the route" is a // closed-form question about one or two stages, and the maze is built around // the answer: route corridors are always open, and every other corridor is // opened by a hash, which is what supplies the side passages, loops and dead // ends. Corners are quarter circles, so the worm bends rather than kinks. // // The one thing that is not closed form is time -> distance along the route, // because stages differ in length. The lanes repeat every 32 stages, so main() // sums one period of stage lengths (a 32-step loop, once per pixel, trivial // next to a raymarch), wraps the head position into it, and copies the eight // stages around the worm into global arrays the distance field walks. // =========================================================================== #define TAU 6.283185307 #define PI 3.14159265 #define MAXSTEP 112 #define SHSTEP 16 #define VOLSTEP 9 #define FAR 34.0 #define LIP 0.72 // ---------------------------------------------------------------- small math mat2 rot(float a){ float c = cos(a), s = sin(a); return mat2(c, s, -s, c); } float hash11(float p){ p = fract(p * 0.1031); p *= p + 33.33; p *= p + p; return fract(p); } float hash12(vec2 p){ vec3 q = fract(vec3(p.xyx) * 0.1031); q += dot(q, q.yzx + 33.33); return fract((q.x + q.y) * q.z); } float vn2(vec2 p){ vec2 i = floor(p), f = fract(p); f = f * f * (3.0 - 2.0 * f); return mix(mix(hash12(i), hash12(i + vec2(1.0, 0.0)), f.x), mix(hash12(i + vec2(0.0, 1.0)), hash12(i + vec2(1.0, 1.0)), f.x), f.y); } // Does the duct from node lo along axis ax have a bulkhead? Shared by the plate, // the worm's squeeze and the beam so they can never disagree. Not every duct: // with a plate in all of them a camera riding the route spent half its time // looking at the back of one. float portAt(vec3 lo, int ax){ return step(hash12(vec2(lo.x * 13.1 + lo.y * 7.7 + float(ax) * 3.3, lo.z * 1.37 + 0.5)), 0.45); } float sdBox2(vec2 p, vec2 b){ vec2 d = abs(p) - b; return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); } float sdBox3(vec3 p, vec3 b){ vec3 d = abs(p) - b; return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0)); } float rep(float x, float c){ return x - c * floor(x / c + 0.5); } float lum(vec3 c){ return dot(c, vec3(0.2126, 0.7152, 0.0722)); } // ---------------------------------------------------------------- globals // Everything here is written once per pixel by setup(), before the march. float gC; // node pitch float gRC; // radius of the route's corners float gW; // route lanes run -gW..gW; the maze is one lane wider each side float gNF; // floors vec2 gH; // corridor half-extent (across, up) float gJ; // chamber half-extent float gRP; // port radius float gR0; // nominal body radius float gNeed; // body scale that fits the port float gA; // weave amplitude float gSEG; // plate pitch float gL; // body length float gHead; // route distance of the nose float gCut; // overhead view: everything above this height is cut away float gEye; // observer lamp multiplier vec3 gLampP; // headlamp vec3 gLampD; vec3 gLampN; // node the headlamp is nearest vec3 gArcP; // live arc, if any float gArcA; vec3 gCamP; float gWu; // body coordinate, spine offset and squeeze of the last worm hit vec2 gWe; float gWsq; float gFlick; // the headlamp is not well vec3 gCamRo; // camera position and look target, from the state pass vec3 gCamTgt; vec3 gCamD; vec3 gBL0; // three lights riding the body vec3 gBL1; vec3 gBL2; vec3 gBMin; // bounds of the body, for skipping the worm entirely vec3 gBMax; // The route around the worm, flattened: eight stages of six elements each. // Element k is a straight run (kind 1), a quarter-circle corner (kind 2), or // absent (kind 0, length 0). For a run, S is its start and A its direction; for // a corner, S is the vertex, A the direction in and B the direction out. // // It is flat on purpose. The first build walked stages and asked a function for // each stage's elements, two nested loops with a six-way branch inside, and // ANGLE's D3D backend took 76 seconds to link it. vec3 gES[48]; vec3 gEA[48]; vec3 gEB[48]; float gEK[48]; float gEL[48]; float gEU[48]; // route distance at the element start float gSu0[8]; // route distance at the start of each of the eight window stages float gSBase; // stage index of the first of them // ---------------------------------------------------------------- the route // Value noise with an integer period, so the lanes repeat exactly and the // stage-length table below can be summed once. float vnoise(float x, float per, float seed){ float i = floor(x), f = fract(x); float a = hash11(mod(i, per) * 7.31 + seed); float b = hash11(mod(i + 1.0, per) * 7.31 + seed); float v = mix(a, b, f * f * (3.0 - 2.0 * f)); return clamp((v - 0.5) * 1.7 + 0.5, 0.0, 0.999); } float laneX(float s){ return floor(vnoise(s * 0.5, 16.0, 1.7) * (2.0 * gW + 1.0)) - gW; } float laneY(float s){ return floor(vnoise(s * 0.25, 8.0, 9.3) * gNF); } float stageLen(float s){ float x0 = laneX(s), x1 = laneX(s + 1.0), x2 = laneX(s + 2.0); float y0 = laneY(s), y1 = laneY(s + 1.0), y2 = laneY(s + 2.0); float dx = abs(x1 - x0), dy = abs(y1 - y0); float hx = step(0.5, dx), hy = step(0.5, dy); float k = 2.0 * hx + 2.0 * hy - hx * hy; float cn = max(step(0.5, abs(x2 - x1)), step(0.5, abs(y2 - y1))); return gC * (1.0 + dx + dy) - gRC * cn + step(0.5, k) * (k * gRC * (PI * 0.5 - 2.0) + gRC); } // The body. Machined, not grown: faceted segments with real gaps between them, // an exposed drive shaft bridging the gaps, a dorsal rail, radii that step down // per segment instead of tapering, and flat end caps. Returns the segment radius // and which part won, so the material can shade shaft and rail differently. float bodyD(vec2 e, float u, float sq, out float r, out float part){ float si = floor(u / gSEG); float ts = clamp((si + 0.5) * gSEG / gL, 0.0, 1.0); r = gR0 * sq * (1.0 - 0.42 * smoothstep(0.45, 1.0, ts)) * (1.0 + 0.10 * step(ts, 0.10)); float uf = u - (si + 0.5) * gSEG; vec2 a2 = abs(e); float oc = max(max(a2.x, a2.y) - r, (a2.x + a2.y) * 0.7071 - r * 0.93); // octagon float h = abs(uf) - gSEG * 0.40; float d = min(max(oc, h), 0.0) + length(max(vec2(oc, h), 0.0)) - 0.015; part = 0.0; float core = length(e) - r * 0.52; if (core < d) { d = core; part = 1.0; } float rail = sdBox2(vec2(e.x, e.y - r * 0.86), vec2(r * 0.34, r * 0.15)) - 0.012; if (rail < d) { d = rail; part = 2.0; } // The stinger: the last 0.7 of the body narrows to a faceted point. (It had four // swept blades too; from the follow camera they read as a giant X.) float tl = u - (gL - 0.7); if (tl > 0.0) { float k = 1.0 - tl / 0.7; float rs = gR0 * 0.45 * k; float cone = max(max(a2.x, a2.y) - rs, (a2.x + a2.y) * 0.7071 - rs * 0.93); d = cone; part = 3.0; } return d; } // Sideways for a corridor running along a. Chosen so cross(a, perp) is +y in // every horizontal corridor, which keeps the worm's belly on the floor. vec3 perpOf(vec3 a){ return abs(a.x) > 0.5 ? vec3(0.0, 0.0, -a.x) : vec3(1.0, 0.0, 0.0); } // Distance from the nearest node along one axis, and which side of it. float nodeDist(float c, out float side){ float mc = c - gC * floor(c / gC); side = mc < gC * 0.5 ? 1.0 : -1.0; return min(mc, gC - mc); } // The serpentine: one S between a node and the next port, zero at both, so it // meets the corner arcs (which do not weave) and the ports (which it has to // thread) exactly on the centreline. float weaveAmt(float dn, float side){ float sn = clamp((dn - gRC) / (gC * 0.5 - gRC), 0.0, 1.0); return gA * sin(PI * sn) * side; } // A point on the route at distance A, and the direction of travel there. vec3 pathAt(float A, bool weave, out vec3 tn){ A = clamp(A, gEU[0], gEU[47] + gEL[47] - 0.001); vec3 pos = gES[0]; tn = vec3(0.0, 0.0, 1.0); for (int k = 0; k < 48; k++) { float a = A - gEU[k]; if (gEL[k] > 0.0 && a >= 0.0 && a < gEL[k]) { if (gEK[k] > 1.5) { float th = a / gRC; vec3 O = gES[k] - gEA[k] * gRC + gEB[k] * gRC; pos = O + gRC * (gEA[k] * sin(th) - gEB[k] * cos(th)); tn = gEA[k] * cos(th) + gEB[k] * sin(th); } else { pos = gES[k] + gEA[k] * a; tn = gEA[k]; if (weave) { float side; float dn = nodeDist(dot(pos, tn), side); pos += perpOf(tn) * weaveAmt(dn, side); } } } } return pos; } // Distance to the body. Hands back the body coordinate u (distance behind the // nose), the 2D offset from the spine in the winning element cross-section // (for fins and texture), and the radius and squeeze used there. // Route distance at the start of stage s, picked out of the eight window // stages arithmetically (an array index here would have to be a loop index). float stageU0(float s){ float i = s - gSBase, r = 0.0; for (int k = 0; k < 8; k++) r += gSu0[k] * (1.0 - step(0.5, abs(i - float(k)))); return r; } // The body around one straight run starting at S along a, length len, whose // start is route distance u0. Updates the running best. void segBody(vec3 p, vec3 S, vec3 a, float len, float u0, inout float best, inout float bu, inout vec2 be, inout float brw, inout float bsq){ vec3 w = p - S; float t = clamp(dot(w, a), 0.0, max(len, 0.0)); float side; float dn = nodeDist(dot(S + a * t, a), side); vec3 P = perpOf(a); vec3 e = w - a * t - P * weaveAmt(dn, side); // the port sits at the midpoint between nodes vec3 pm = S + a * t; int pax = abs(a.x) > 0.5 ? 0 : (abs(a.y) > 0.5 ? 1 : 2); vec3 plo = floor(pm / gC + 0.5); if (pax == 0) plo.x = floor(pm.x / gC); else if (pax == 1) plo.y = floor(pm.y / gC); else plo.z = floor(pm.z / gC); float sq = mix(1.0, gNeed, (1.0 - smoothstep(0.0, 0.42, gC * 0.5 - dn)) * portAt(plo, pax)); float u = gHead - (u0 + t); vec2 e2 = vec2(dot(e, P), dot(e, cross(a, P))); float rw, part; // past the ends of this run the 2D section says nothing about the axial gap, // so cap it -- without this the body continued as an endless prism behind // the run, straight through the follow camera float dd = max(max(bodyD(e2, u, sq, rw, part), abs(dot(w, a) - t)), max(-u, u - gL)); if (dd < best) { best = dd; bu = u; be = e2; brw = rw; bsq = sq; } } // The body around one quarter-circle corner at vertex V, turning from a to b. void arcBody(vec3 p, vec3 V, vec3 a, vec3 b, float u0, inout float best, inout float bu, inout vec2 be, inout float brw, inout float bsq){ vec3 O = V - a * gRC + b * gRC; vec3 w = p - O; float c1 = dot(w, a), c2 = -dot(w, b); float h = dot(w, cross(a, b)); float rad, along; vec2 e2; if (c1 >= 0.0 && c2 >= 0.0) { // inside the quarter: exact torus distance, and the exact angle. A ratio // stood in for atan here until it was found to be 0.06 out -- exactly the // head camera standoff -- which put that camera inside the nose on corners. e2 = vec2(length(vec2(c1, c2)) - gRC, h); rad = length(e2); along = gRC * atan(c1, c2); } else { float th = c1 < 0.0 ? 0.0 : PI * 0.5; rad = length(p - (O + gRC * (a * sin(th) - b * cos(th)))); e2 = vec2(rad, 0.0); along = gRC * th; } float u = gHead - (u0 + along); float rw, part; float dd = max(bodyD(e2, u, 1.0, rw, part), max(-u, u - gL)); if (dd < best) { best = dd; bu = u; be = e2; brw = rw; bsq = 1.0; } } // Distance to the body, built around the node nearest p only. The route passes // a node in one of five roles -- stage start, inside the sideways run, end of // that run, inside the climb, end of the climb -- and each role is fully // described by a direction in, a direction out, whether it turns, and the route // distance where its corner begins. The body near the node is then the half-run // arriving from the previous midpoint, the corner, and the half-run leaving to // the next midpoint; neighbouring nodes' half-runs meet exactly at those // midpoints. Three element bodies, whatever the stage looks like. float wormDist(vec3 p, float dMax, out float bu, out vec2 be, out float brw, out float bsq){ float best = 1e9; bu = 1e3; be = vec2(1.0, 0.0); brw = gR0; bsq = 1.0; vec3 n = floor(p / gC + 0.5); vec3 l = abs(p - n * gC); // never claim more clearance than the way out of this node's cell: whatever // is past that face belongs to the neighbour, which the next step will ask float face = gC * 0.5 - max(l.x, max(l.y, l.z)) + 0.15; float s = n.z; if (s < gSBase + 0.5 || s > gSBase + 7.5) return face; float x0 = laneX(s), x1 = laneX(s + 1.0), y0 = laneY(s), y1 = laneY(s + 1.0); float dx = x1 - x0, dy = y1 - y0; float hx = step(0.5, abs(dx)), hy = step(0.5, abs(dy)), hk = max(hx, hy); vec3 ex = vec3(sign(dx), 0.0, 0.0), ey = vec3(0.0, sign(dy), 0.0), ez = vec3(0.0, 0.0, 1.0); float u0 = stageU0(s); float arcL = gRC * PI * 0.5; float runX = hx * (abs(dx) * gC - 2.0 * gRC + arcL); // sideways run plus its end corner // which role, if any (earlier roles win where two coincide) float atY0 = 1.0 - step(0.5, abs(n.y - y0)); float atX1 = 1.0 - step(0.5, abs(n.x - x1)); float m0 = (1.0 - step(0.5, abs(n.x - x0))) * atY0; float m1 = hx * atX1 * atY0 * (1.0 - m0); float m2 = hy * atX1 * (1.0 - step(0.5, abs(n.y - y1))) * (1.0 - m0) * (1.0 - m1); float mx = hx * atY0 * step(min(x0, x1) + 0.5, n.x) * step(n.x, max(x0, x1) - 0.5); float my = hy * atX1 * step(min(y0, y1) + 0.5, n.y) * step(n.y, max(y0, y1) - 0.5); float on = m0 + m1 + m2 + mx + my; if (on < 0.5) return face; vec3 aIn = m0 * ez + (m1 + mx) * ex + (m2 + my) * ey; vec3 out0 = hx > 0.5 ? ex : (hy > 0.5 ? ey : ez); vec3 aOut = m0 * out0 + m1 * (hy > 0.5 ? ey : ez) + mx * ex + (m2 + my) * ez; aOut = my > 0.5 ? ey : aOut; float turn = m0 * hk + m1 + m2; float nodeU = m0 * u0 + mx * (u0 + hk * arcL + abs(n.x - x0) * gC - gRC) + m1 * (u0 + arcL + abs(dx) * gC - 2.0 * gRC) + my * (u0 + hk * arcL + runX + abs(n.y - y0) * gC - gRC) + m2 * (u0 + hk * arcL + runX + abs(dy) * gC - 2.0 * gRC); vec3 V = n * gC; float rcN = turn * gRC; float hl = gC * 0.5 - rcN; segBody(p, V - aIn * gC * 0.5, aIn, hl, nodeU - hl, best, bu, be, brw, bsq); if (turn > 0.5) arcBody(p, V, aIn, aOut, nodeU, best, bu, be, brw, bsq); segBody(p, V + aOut * rcN, aOut, hl, nodeU + turn * arcL, best, bu, be, brw, bsq); return min(best, face); } // ---------------------------------------------------------------- the maze vec3 axisVec(int ax){ return ax == 0 ? vec3(1.0, 0.0, 0.0) : (ax == 1 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, 0.0, 1.0)); } bool inBand(vec3 n){ return abs(n.x) < gW + 1.5 && n.y > -0.5 && n.y < gNF - 0.5; } // Is the corridor from node lo to lo + axis open? Route corridors always are. float edgeOpen(vec3 lo, int ax){ vec3 hi = lo + axisVec(ax); if (!inBand(lo) || !inBand(hi)) return 0.0; float s = lo.z; if (ax == 2) { if (abs(lo.x - laneX(s + 1.0)) < 0.5 && abs(lo.y - laneY(s + 1.0)) < 0.5) return 1.0; } else if (ax == 0) { float x0 = laneX(s), x1 = laneX(s + 1.0); if (abs(lo.y - laneY(s)) < 0.5 && lo.x > min(x0, x1) - 0.5 && lo.x < max(x0, x1) - 0.5) return 1.0; } else { float y0 = laneY(s), y1 = laneY(s + 1.0); if (abs(lo.x - laneX(s + 1.0)) < 0.5 && lo.y > min(y0, y1) - 0.5 && lo.y < max(y0, y1) - 0.5) return 1.0; } float dens = uBranch * (ax == 1 ? 0.22 : (ax == 2 ? 0.62 : 0.50)); return step(hash12(vec2(lo.x * 57.0 + lo.y * 131.0 + float(ax) * 17.0, lo.z)), dens); } // Nearest node, offset from it, and the corridor frame of the dominant axis. // Taking only the dominant axis is exact for membership: chambers are cubes at // least as wide as any corridor, so a point outside its chamber can only be // inside the corridor along its largest offset. Leaving the other corridors // out only ever shortens a distance, never lengthens one. void cell(vec3 p, out vec3 n, out vec3 l, out int ax, out float axial, out vec2 q, out float z){ n = floor(p / gC + 0.5); n.x = clamp(n.x, -gW - 1.0, gW + 1.0); n.y = clamp(n.y, 0.0, gNF - 1.0); l = p - n * gC; vec3 al = abs(l); ax = 2; axial = l.z; q = l.xy; z = p.z; if (al.x > al.y && al.x > al.z) { ax = 0; axial = l.x; q = vec2(l.z, l.y); z = p.x + 31.7; } else if (al.y > al.z) { ax = 1; axial = l.y; q = vec2(l.x, l.z); z = p.y + 67.1; } } // ---------------------------------------------------------------- board cell // c = (depth inward from the board face, across the duct, along the duct). // Treating the inward depth as a Cartesian axis is only valid on the flat part // of the wall, which is why map() clips the boards away from the corners. float boardCell(vec3 c, float h, out float id){ float ha = fract(h * 17.0); float hb = fract(h * 53.0); float k = 0.55 + 0.45 * uClutter; // CLUTTER shortens everything as well as thinning it float d; id = 3.0; if (h < 0.26) { // a leadframe package: flat slug, two combs of pins vec2 hs = vec2(0.070 + 0.048 * ha, 0.048 + 0.052 * hb); float t = (0.028 + 0.022 * ha) * k; d = sdBox3(vec3(c.x - t, c.y, c.z), vec3(t, hs.x, hs.y)) - 0.006; float pz = rep(c.z, 0.028); float pin = sdBox3(vec3(c.x - 0.010, abs(c.y) - (hs.x + 0.024), pz), vec3(0.010, 0.024, 0.005)); pin = max(pin, abs(c.z) - hs.y); if (pin < d) { d = pin; id = 7.0; } } else if (h < 0.44) { // electrolytic can, standing off the board float rr = (0.048 + 0.032 * ha); float hg = (0.09 + 0.10 * hb) * k; d = max(length(c.yz) - rr, abs(c.x - hg * 0.5) - hg * 0.5) - 0.008; id = 4.0; } else if (h < 0.55) { // pin header float pz = rep(c.z, 0.048); d = sdBox3(vec3(c.x - 0.040 * k, c.y, pz), vec3(0.040 * k, 0.015, 0.009)); d = max(d, abs(c.z) - (0.055 + 0.06 * ha)); id = 7.0; } else if (h < 0.66) { // finned heatsink over something that runs hot float fz = rep(c.z, 0.030); d = sdBox3(vec3(c.x - 0.055 * k, c.y, fz), vec3(0.055 * k, 0.080, 0.006)); d = max(d, abs(c.z) - 0.095); d = min(d, sdBox3(vec3(c.x - 0.011, c.y, c.z), vec3(0.011, 0.086, 0.100))); id = 12.0; } else if (h < 0.74) { // indicator LED d = length(vec3(c.x - 0.010, c.yz)) - 0.024; id = 10.0; } else { // SMD chaff sitting almost flat d = sdBox3(vec3(c.x - 0.006, c.y, c.z), vec3(0.006, 0.018, 0.032)) - 0.003; id = 11.0; } return d; } // Boards, looms and conduits along one corridor, in its own frame. Clipped at // the chamber mouth (`cut`) so none of it hangs into a junction. float corridorDetail(vec2 q, float z, float axial, float d, inout float id){ float cut = gJ + 0.05 - abs(axial); float sx = step(q.x, 0.0); // 1 on the far wall: shifts its grid float inx = gH.x - abs(q.x); vec2 bc = vec2(q.y + sx * 0.23, z + sx * 1.73); vec2 bid = floor(bc / 0.36); vec2 bf = bc - (bid + 0.5) * 0.36; float h = hash12(bid + vec2(sx * 31.0, 7.0)); if (fract(h * 211.0) < 0.30 + 0.70 * uClutter) { float cid; float dC = boardCell(vec3(inx, bf.x, bf.y), h, cid); dC = max(max(dC, abs(q.y) - (gH.y - 0.30)), cut); if (dC < d) { d = dC; id = cid; } } if (uWires > 0.001) { vec2 aq = abs(q); vec2 sg = sign(q) + vec2(0.001); vec2 cc = vec2(gH.x - 0.21, gH.y - 0.20) + vec2(sin(z * 0.47 + sg.x * 1.7), sin(z * 0.39 + sg.y * 2.3)) * 0.035; vec2 bq = aq - cc; float rr = 0.033 * uWires; float sp = 0.062 * uWires; float dWi = length(bq) - rr; float tw = z * 0.34 + sg.x * 0.9 + sg.y * 2.1; vec2 o = vec2(cos(tw), sin(tw)) * sp; for (int k = 0; k < 4; k++) { dWi = min(dWi, length(bq - o) - rr * 0.92); o = vec2(-o.y, o.x); // exact 90 degrees: no trig in the loop } dWi = max(dWi, cut); if (dWi < d) { d = dWi; id = 5.0; } float zt = rep(z, 0.95); float dT = max(max(length(bq) - (sp + rr + 0.020), abs(zt) - 0.016), (sp + rr + 0.003) - length(bq)); dT = max(dT, cut); if (dT < d) { d = dT; id = 13.0; } } float ci = floor(z / 2.6 + 0.5); if (hash11(ci * 5.7) < 0.45 * uClutter) { float dP = length(vec2(z - ci * 2.6, abs(q.y) - (gH.y - 0.052))) - 0.042; dP = max(dP, cut); if (dP < d) { d = dP; id = 14.0; } } return d; } // ---------------------------------------------------------------- the map vec2 mapW(vec3 p, bool withWorm, bool withDetail){ vec3 n, l; int ax; float axial; vec2 q; float z; cell(p, n, l, ax, axial, q, z); // ---- carve: the chamber at this node, plus the corridor along the dominant // axis if it is open. The piece runs past the midpoint so the neighbouring // node's half meets it without an end face. float sg = axial >= 0.0 ? 1.0 : -1.0; vec3 lo = sg > 0.0 ? n : n - axisVec(ax); float open = edgeOpen(lo, ax); float dBox = sdBox3(l, vec3(gJ - 0.16)) - 0.16; float dCor = 1e9; float hl = gC * 0.25 + 0.3; if (open > 0.5) dCor = max(sdBox2(q, gH - 0.14) - 0.14, abs(abs(axial) - hl) - hl); float d = -min(dBox, dCor); float id = dCor < dBox ? 1.0 : 16.0; if (open > 0.5) { if (withDetail && d < 0.62 && abs(axial) > gJ - 0.2) d = corridorDetail(q, z, axial, d, id); // ---- the bulkhead halfway along, and the port through it if (portAt(lo, ax) > 0.5) { float zl = gC * 0.5 - abs(axial); // octagonal port, cut to match the worm's facets, through a plate with a // machined collar standing proud of it on both faces vec2 aq = abs(q); float oct = max(max(aq.x, aq.y), (aq.x + aq.y) * 0.7071); float dB = max(abs(zl) - 0.07, gRP - oct) - 0.010; dB = min(dB, max(max(abs(zl) - 0.17, abs(oct - gRP - 0.07) - 0.07), gRP - oct) - 0.012); if (dB < d) { d = dB; id = 6.0; } if (withDetail && abs(zl) < 0.3) { // four clamp blocks gripping the collar vec2 fq = aq.x > aq.y ? aq : aq.yx; float dO = sdBox3(vec3(fq.x - gRP - 0.08, fq.y, abs(zl) - 0.19), vec3(0.035, 0.05, 0.03)) - 0.006; if (dO < d) { d = dO; id = 7.0; } } } } // ---- the worm, skipped outright when this point is nowhere near it vec3 bc = (gBMin + gBMax) * 0.5; if (withWorm && sdBox3(p - bc, (gBMax - gBMin) * 0.5) < d) { float bu, brw, bsq; vec2 be; float dW = wormDist(p, d, bu, be, brw, bsq); if (dW < d) { d = dW; id = 8.0; gWu = bu; gWe = be; gWsq = bsq; } if (uFins > 0.001 && dW < 0.46 && bu > 0.18 && bu < gL - 0.7) { float si = floor(bu / gSEG); float lz = bu - (si + 0.5) * gSEG; float a = hash11(si * 1.7) * TAU + sin(bu * 1.1 - TIME * 4.0 * max(uSpeed, 0.25)) * 0.45; vec2 er = rot(-a) * be; float fl = 0.15 * uFins * bsq; float ax2 = abs(er.x) - brw; float dF = sdBox3(vec3(ax2 - fl * 0.5, er.y, lz + ax2 * 0.55), vec3(fl * 0.5, 0.011, 0.045 * (1.0 - 0.55 * clamp(ax2 / max(fl, 1e-3), 0.0, 1.0)))) - 0.006; if (dF < d) { d = dF; id = 15.0; gWu = bu; gWe = be; gWsq = bsq; } } } return vec2(d, id); } vec2 map(vec3 p){ return mapW(p, true, true); } // Tetrahedral normal as a loop: one inlined copy of map() instead of four. vec3 normalAt(vec3 p, float t){ float h = 0.0009 + 0.0012 * t; vec3 n = vec3(0.0); for (int i = 0; i < 4; i++) { vec3 e = i == 0 ? vec3(1.0, -1.0, -1.0) : (i == 1 ? vec3(-1.0, -1.0, 1.0) : (i == 2 ? vec3(-1.0, 1.0, -1.0) : vec3(1.0, 1.0, 1.0))); n += e * map(p + e * h).x; } return normalize(n); } float softShadow(vec3 ro, vec3 rd, float mx){ float res = 1.0, t = 0.05; for (int i = 0; i < SHSTEP; i++) { // board-scale detail casts nothing worth a whole copy of it in the compile, and // neither does the worm: it trails behind its own headlamp float h = mapW(ro + rd * t, false, false).x * LIP; res = min(res, 11.0 * h / t); t += clamp(h, 0.025, 0.55); if (res < 0.02 || t > mx) break; } return clamp(res, 0.0, 1.0); } // Can the headlamp see this point of air? The beam lives in corridors, so the // answer is lattice-shaped: the lamp's own node sees everything in it; a // neighbouring node along one axis sees it only through an open corridor and // only through the port in that corridor's bulkhead; anything further is dark. // Without this the beam glows through solid walls into parallel corridors. float beamOcc(vec3 x){ vec3 dn = floor(x / gC + 0.5) - gLampN; vec3 ad = abs(dn); float m = ad.x + ad.y + ad.z; if (m < 0.5) return 1.0; if (m > 1.5) return 0.0; int ax = ad.x > 0.5 ? 0 : (ad.y > 0.5 ? 1 : 2); vec3 e = axisVec(ax); float sg = dot(dn, e); vec3 lo = sg > 0.0 ? gLampN : gLampN - e; if (edgeOpen(lo, ax) < 0.5) return 0.0; float mid = (dot(lo, e) + 0.5) * gC; float ta = dot(gLampP, e), tb = dot(x, e); vec3 c = mix(gLampP, x, clamp((mid - ta) / (tb - ta), 0.0, 1.0)); vec3 off = c - (lo + e * 0.5) * gC; off -= e * dot(off, e); return max(1.0 - portAt(lo, ax), smoothstep(gRP, gRP * 0.7, length(off))); } // ---------------------------------------------------------------- surfacing // PCB traces. Each cell of a coarse grid holds a straight run or a quarter // turn, which is the whole visual grammar of a board: right angles and 45s that // meet. Two layers at different scales and seeds read as signal over ground. float traceD(vec2 uv, float sd){ vec2 g = uv * 3.4; vec2 i2 = floor(g); vec2 f = fract(g) - 0.5; float h = hash12(i2 + sd); if (h < 0.38) return abs(f.y); if (h < 0.70) return abs(f.x); if (h < 0.85) return abs(length(f - vec2(-0.5, -0.5)) - 0.5); return abs(length(f - vec2(0.5, -0.5)) - 0.5); } // How filthy this spot is. Streaks run down the walls, dust settles on anything // facing up, soot collects in the corners of a duct, and patches of corrosion sit // wherever they like. One function, used by every surface in the place. float grimeAt(vec3 p, vec3 n, vec2 q){ float streak = vn2(vec2((p.x + p.z) * 14.0, p.y * 0.8)) * (0.5 + 0.5 * vn2(vec2((p.x + p.z) * 3.0, 0.0))); float dust = max(n.y, 0.0) * 0.8; float corner = 1.0 - smoothstep(0.0, 0.45, min(gH.x - abs(q.x), gH.y - abs(q.y))); float blot = vn2(p.xz * 1.7 + p.y * 1.3); return clamp((0.30 * streak + 0.35 * dust + 0.45 * corner + 0.30 * blot) * uGrime, 0.0, 1.0); } vec3 armorCol(out float rgh, out float mtl){ if (uArmor == 1) { rgh = 0.42; mtl = 0.35; return vec3(0.075, 0.080, 0.092); } if (uArmor == 2) { rgh = 0.26; mtl = 1.00; return vec3(0.92, 0.53, 0.28 ); } if (uArmor == 3) { rgh = 0.52; mtl = 0.05; return vec3(0.88, 0.86, 0.79 ); } if (uArmor == 4) { rgh = 0.44; mtl = 0.10; return vec3(0.86, 0.62, 0.08 ); } if (uArmor == 5) { rgh = 0.08; mtl = 1.00; return vec3(0.85, 0.87, 0.90 ); } if (uArmor == 6) { rgh = 0.68; mtl = 0.55; return vec3(0.44, 0.20, 0.11 ); } if (uArmor == 7) { rgh = 0.36; mtl = 0.25; return vec3(0.10, 0.105, 0.118); } rgh = 0.30; mtl = 1.00; return vec3(0.62, 0.64, 0.67); } void material(vec3 p, vec3 n, float id, out vec3 alb, out float rgh, out float mtl, out vec3 emi){ vec3 nd, l; int ax; float axial; vec2 q; float z; cell(p, nd, l, ax, axial, q, z); alb = vec3(0.5); rgh = 0.5; mtl = 0.0; emi = vec3(0.0); float wu = gWu, wsq = gWsq; vec2 we = gWe; if (id < 1.5) { // ---- the duct wall. The flat side faces are board; the roof and floor are // vented sheet. if (abs(q.x) > gH.x - 0.17 && abs(q.y) < gH.y - 0.30) { vec2 uv = vec2(z, q.y) * 1.9; float board = hash12(floor(vec2(z, q.y) * 0.28)); alb = mix(vec3(0.022, 0.048, 0.030), vec3(0.035, 0.030, 0.028), step(0.55, board)); rgh = 0.62; float t1 = smoothstep(0.055, 0.026, traceD(uv, 0.0)); float t2 = smoothstep(0.050, 0.024, traceD(uv * 1.73 + 11.0, 3.0)); float tr = max(t1, t2 * 0.75); alb = mix(alb, vec3(0.34, 0.26, 0.10), tr); // tarnished tin rgh = mix(rgh, 0.28, tr); mtl = tr * 0.8; // silkscreen: thin white outlines on a coarser grid vec2 sg = fract(vec2(z, q.y) * 2.8) - 0.5; float sk = smoothstep(0.015, 0.0, abs(sdBox2(sg, vec2(0.30, 0.22)))); alb = mix(alb, vec3(0.72), sk * 0.5); emi = vec3(0.10, 0.45, 0.32) * tr * 0.03 * uLeds; } else { alb = vec3(0.075, 0.072, 0.068); rgh = 0.66; mtl = 0.45; // panel seams float sm = min(abs(rep(z, 0.78)), abs(rep(q.y, 0.62))); alb *= 1.0 - 0.55 * smoothstep(0.016, 0.004, sm); // louvre slots on the roof and floor float sl = abs(rep(q.x, 0.10)); float mask = step(abs(q.y), gH.y + 0.01) * step(gH.y - 0.30, abs(q.y)); alb *= 1.0 - 0.60 * smoothstep(0.030, 0.018, sl) * mask * step(0.55, hash11(floor(z / 0.62 + 0.5) * 3.1)); rgh = mix(rgh, 0.70, 0.4); } } else if (id < 3.5) { alb = vec3(0.030, 0.031, 0.034); rgh = 0.48; mtl = 0.10; // moulded package float mk = hash12(floor(vec2(z, q.y) * 3.0)); alb += vec3(0.05) * smoothstep(0.9, 1.0, mk); } else if (id < 4.5) { // capacitor: sleeve, with a bright top disc where the normal faces inward float face = abs(dot(n, normalize(vec3(sign(q.x), 0.0, 0.0)))); alb = mix(vec3(0.045, 0.050, 0.075), vec3(0.55, 0.56, 0.58), step(0.8, face)); rgh = mix(0.42, 0.30, step(0.8, face)); mtl = mix(0.15, 0.9, step(0.8, face)); float stq = smoothstep(0.55, 0.75, abs(sin(q.y * 42.0))); alb = mix(alb, vec3(0.68), stq * 0.25 * (1.0 - step(0.8, face))); } else if (id < 5.5) { // wire insulation, coloured per strand vec2 aq = abs(q); vec2 cc = vec2(gH.x - 0.21, gH.y - 0.20); vec2 bq = aq - cc; float a = atan(bq.y, bq.x) + z * 0.34; float k = floor(a / TAU * 4.0 + 0.5) + 4.0 * step(length(bq), 0.05); float hk = hash11(k * 2.7 + sign(q.x) * 3.1 + sign(q.y) * 7.3); // insulation, but decades of it: mostly black and grey, a couple of faded // colours left, all of it filthy alb = 0.5 + 0.5 * cos(TAU * (hk + vec3(0.0, 0.33, 0.67))); alb = mix(vec3(0.055, 0.052, 0.050), alb * 0.34, step(0.55, hk)); rgh = 0.62; mtl = 0.0; } else if (id < 6.5) { // bulkhead: gunmetal plate, bright machined collar, iris seams, stencils, and a // light ring set into the face that half of them no longer power vec2 aq = abs(q); float oct = max(max(aq.x, aq.y), (aq.x + aq.y) * 0.7071); alb = vec3(0.095, 0.10, 0.108); rgh = 0.52; mtl = 0.85; float col = step(oct, gRP + 0.145); alb = mix(alb, vec3(0.24, 0.24, 0.25), col); rgh = mix(rgh, 0.28, col); // eight radial iris seams (integer count, or atan's branch cut prints one more) float sa = abs(fract(atan(q.y, q.x) / TAU * 8.0) - 0.5) * oct * TAU / 8.0; float seam = min(smoothstep(0.012, 0.004, sa) * (1.0 - col), 1.0) + smoothstep(0.010, 0.003, abs(oct - gRP - 0.36)) + smoothstep(0.010, 0.003, abs(oct - gRP - 0.62)); alb *= 1.0 - 0.7 * clamp(seam, 0.0, 1.0); // stencilled warning blocks above and below the port, mostly worn off vec2 sb = vec2(aq.x, aq.y - gRP - 0.47); float stn = step(abs(sb.x), 0.20) * step(abs(sb.y), 0.045) * step(0.5, fract((q.x + q.y) * 9.0)); alb = mix(alb, vec3(0.45, 0.31, 0.04), stn * 0.5); // the light ring float lr = smoothstep(0.012, 0.0, abs(oct - gRP - 0.19)); float live = step(0.5, hash11(dot(nd, vec3(3.1, 17.0, 1.3)))); emi = vec3(0.25, 0.80, 0.95) * lr * live * uLeds * 2.2 * (0.55 + 0.45 * step(0.3, fract(TIME * 1.7 + hash11(nd.z)))); } else if (id < 7.5) { alb = vec3(0.46, 0.45, 0.44); rgh = 0.42; mtl = 1.0; // pins and bolts } else if (id < 8.5) { // ---- the worm: plating, the drive shaft in the gaps, the dorsal rail float u = wu; vec2 e = we; float rr, part; bodyD(e, u, wsq, rr, part); float si = floor(u / gSEG); float uf = u - (si + 0.5) * gSEG; float th = atan(e.y, e.x); alb = armorCol(rgh, mtl); vec3 glow = mix(vec3(0.30, 0.80, 0.95), vec3(1.0, 0.45, 0.10), step(3.5, float(uArmor))); if (part > 2.5) { // hardened dark steel, edges ground bright float tlm = clamp((u - (gL - 0.7)) / 0.7, 0.0, 1.0); float reach = rr * 0.45 * (1.0 - tlm); float edge = smoothstep(0.55, 1.0, ((abs(e.x) + abs(e.y)) * 0.7071) / max(reach, 1e-3)); alb = mix(vec3(0.07, 0.07, 0.075), vec3(0.62, 0.60, 0.58), edge); rgh = mix(0.40, 0.12, edge); mtl = 1.0; } else if (part > 1.5) { alb = vec3(0.30, 0.31, 0.33) * (0.7 + 0.5 * hash12(floor(vec2(u * 40.0, 0.0)))); rgh = 0.30; mtl = 1.0; // rail, worn bright } else if (part > 0.5) { alb = vec3(0.045, 0.046, 0.050); rgh = 0.45; mtl = 0.9; // drive shaft float ring = step(0.55, fract(u * 26.0)); alb *= 0.7 + 0.6 * ring; emi = glow * (0.35 + 0.25 * sin(TIME * 3.0 + si)) * uLeds * 0.9; } else { // plate face: panel edge, stencilled block, hazard stripes on some segments float edge = smoothstep(gSEG * 0.40, gSEG * 0.34, abs(uf)); alb *= 0.55 + 0.45 * edge; float hs = hash11(si * 1.37); if (hs > 0.80) alb = mix(alb, vec3(0.55, 0.40, 0.05), step(0.5, fract(uf * 7.0 + th * 1.2)) * 0.8); else if (hs > 0.62) alb = mix(alb, vec3(0.62), step(0.5, fract(th * 2.0)) * step(abs(uf), gSEG * 0.2) * 0.35); if (uArmor == 7) { float w = step(0.5, fract(u * 11.0)) * step(0.5, fract(th * 4.0)); alb *= 0.75 + 0.5 * w; rgh = 0.28 + 0.2 * w; } } // weathering: soot along the underside, rust eating the plate corners float bel = smoothstep(-0.2, -0.9, normalize(vec3(e, 0.001)).y); float rust = vn2(vec2(u * 9.0, th * 2.5)) * vn2(vec2(u * 2.3 + 7.0, th * 0.9)); alb = mix(alb, vec3(0.20, 0.10, 0.055), clamp(rust * 1.5 - 0.35, 0.0, 0.75) * uGrime); alb *= 1.0 - 0.45 * bel * uGrime; rgh = clamp(rgh + 0.35 * rust * uGrime + 0.2 * bel, 0.05, 0.98); mtl *= 1.0 - 0.5 * rust * uGrime; // a red beacon ring where the stinger meets the body emi += vec3(1.0, 0.09, 0.04) * 3.0 * uLeds * step(gL - 0.7, u) * step(u, gL - 0.63) * (0.45 + 0.55 * step(0.5, fract(TIME * 0.8))); // the head lamp, a hot lens in the nose plate if (u < 0.075) { alb = vec3(0.02); rgh = 0.10; mtl = 0.4; emi += vec3(1.0, 0.82, 0.58) * 22.0 * uLamp * gFlick * smoothstep(0.95, 0.35, length(e) / max(gR0 * 0.7, 1e-3)); } } else if (id < 10.5) { // indicator LED: on, off, or blinking, decided once per board cell float sx = step(q.x, 0.0); vec2 bc = vec2(q.y + sx * 0.23, z + sx * 1.73); float h = hash12(floor(bc / 0.36) + vec2(sx * 31.0, 7.0)); float hk = fract(h * 91.0); float blk = step(0.45, fract(TIME * (0.4 + hk * 3.0) + hk * 5.0)); float on = mix(1.0, blk, step(0.35, hk)); // most of them are dead, and the survivors are not well vec3 lc = hk < 0.30 ? vec3(0.30, 1.0, 0.40) : hk < 0.70 ? vec3(1.0, 0.55, 0.08) : vec3(1.0, 0.16, 0.12); float alive = step(0.45, fract(hk * 313.0)); float sick = 0.55 + 0.45 * step(0.35, fract(TIME * (1.0 + hk * 9.0) + hk)); alb = lc * 0.05; rgh = 0.35; mtl = 0.0; emi = lc * 7.0 * uLeds * on * alive * sick; } else if (id < 11.5) { alb = vec3(0.10, 0.10, 0.11); rgh = 0.44; mtl = 0.2; // SMD chaff } else if (id < 12.5) { alb = vec3(0.40, 0.42, 0.44); rgh = 0.58; mtl = 0.9; // heatsink } else if (id < 13.5) { alb = vec3(0.055, 0.056, 0.060); rgh = 0.50; mtl = 0.0; // zip tie } else if (id > 15.5) { // junction chamber: dark panelling, grated floor, and a status matrix on // the walls -- one blinking pattern per node, so every junction reads as a // different place, which is most of what makes a maze legible vec2 uv = abs(n.x) > 0.5 ? l.zy : (abs(n.y) > 0.5 ? l.xz : l.xy); alb = vec3(0.090, 0.095, 0.108); rgh = 0.50; mtl = 0.70; float seam = min(abs(rep(uv.x, 0.6)), abs(rep(uv.y, 0.6))); alb *= 1.0 - 0.5 * smoothstep(0.014, 0.004, seam); if (n.y > 0.5) { float gr = max(smoothstep(0.012, 0.0, abs(rep(uv.x, 0.09))), smoothstep(0.012, 0.0, abs(rep(uv.y, 0.09)))); alb *= 1.0 - 0.7 * gr; } else if (abs(n.y) < 0.5) { vec2 g = uv * 10.0; vec2 gi = floor(g); float band = step(abs(uv.y - 0.25 * gJ), 0.26) * step(abs(uv.x), 0.7); float hh = hash12(gi + nd.xz * 17.0 + nd.y * 5.0); // a status matrix with most of its pixels burnt out float on = step(0.45, fract(hh * 7.0 + TIME * (0.25 + hh * 0.9))) * step(0.55, fract(hh * 97.0)); float dt = smoothstep(0.32, 0.18, length(fract(g) - 0.5)); vec3 lc = mix(vec3(0.85, 0.42, 0.06), vec3(0.20, 0.85, 0.38), step(0.86, hh)); emi = lc * dt * on * band * 1.8 * uLeds; alb = mix(alb, vec3(0.02), band * 0.8); } } else if (id < 14.5) { // conduit: corrugated flexible tube alb = vec3(0.075, 0.078, 0.085); rgh = 0.55; mtl = 0.3; alb *= 0.78 + 0.30 * smoothstep(0.35, 0.0, abs(rep(z, 0.055))); } else { // anchor fin: bare metal with a worn tip float e2 = length(we); alb = vec3(0.42, 0.43, 0.46); rgh = 0.34; mtl = 1.0; alb *= 0.75 + 0.55 * smoothstep(gR0 * 0.9, gR0 * 1.5, e2); } // ---- and then the whole place is filthy. The worm and anything emissive keep // their own surfacing; everything bolted to the maze wears the same dirt. if (id < 7.9 || id > 10.5) { float gr = grimeAt(p, n, q); alb = mix(alb, alb * vec3(0.62, 0.50, 0.42), gr * 0.85); alb *= 1.0 - 0.45 * gr; rgh = clamp(rgh + 0.30 * gr, 0.05, 0.98); mtl *= 1.0 - 0.55 * gr; // burnt-out cells: one chamber in three is scorched through float burn = smoothstep(0.62, 0.95, hash11(dot(nd, vec3(1.0, 37.0, 7.3)))); alb *= 1.0 - 0.55 * burn * uGrime; emi *= 1.0 - 0.85 * burn; } } // ---------------------------------------------------------------- lighting vec3 shadePt(vec3 p, vec3 n, vec3 v, vec3 alb, float rgh, float mtl, float sh, float occ){ vec3 L = gLampP - p; float dd = dot(L, L); float dist = sqrt(dd); L /= max(dist, 1e-4); float cd = dot(-L, gLampD); float cone = max(smoothstep(cos(uCone * 1.75), cos(uCone * 0.85), cd), 0.10); float att = uLamp * 9.0 * gFlick * cone / (1.0 + dd * 0.95); vec3 col = vec3(0.0); vec3 lc = vec3(1.0, 0.90, 0.74); float ndl = max(dot(n, L), 0.0); vec3 h = normalize(L + v); float sp = pow(max(dot(n, h), 0.0), mix(6.0, 1400.0, pow(1.0 - rgh, 1.6))); vec3 spec = mix(vec3(0.045), alb, mtl) * sp * (1.0 - rgh * 0.55) * 6.0; col += (alb * (1.0 - mtl * 0.82) + spec) * ndl * lc * att * sh; // The observer is holding a lamp. It needs no shadow term -- nothing can be // between a light at the eye and a surface the eye can see -- so it is the // cheapest light in the scene as well as the one doing most of the work, and // being warm against the cold seams is what stops the frame going monochrome. vec3 C = gCamP - p; float cdd = dot(C, C); C *= inversesqrt(max(cdd, 1e-6)); vec3 ch = normalize(C + v); float csp = pow(max(dot(n, ch), 0.0), mix(6.0, 1400.0, pow(1.0 - rgh, 1.6))); col += (alb * (1.0 - mtl * 0.82) + mix(vec3(0.045), alb, mtl) * csp * (1.0 - rgh * 0.55) * 1.8) * max(dot(n, C), 0.0) * vec3(1.0, 0.83, 0.62) * (uLamp * 3.4 * gEye * smoothstep(-0.15, 0.45, dot(-C, gCamD)) / (1.0 + cdd * 0.85 / gEye)); // The worm is a light. Its seams are lit from inside, and a glowing body // that does not spill onto the wall beside it reads as a decal -- three // point lights riding the route along the body stand in for the line. // Surfaces on the worm itself barely see them: their normals face away. vec3 bc = mix(vec3(0.25, 0.85, 1.0), vec3(1.0, 0.55, 0.15), step(3.5, float(uArmor))); vec3 B = gBL0 - p; float bd = dot(B, B); col += (alb + spec * 0.3) * max(dot(n, B * inversesqrt(max(bd, 1e-6))), 0.0) * bc * uLeds * 0.36 / (1.0 + bd * 1.9); B = gBL1 - p; bd = dot(B, B); col += (alb + spec * 0.3) * max(dot(n, B * inversesqrt(max(bd, 1e-6))), 0.0) * bc * uLeds * 0.36 / (1.0 + bd * 1.9); B = gBL2 - p; bd = dot(B, B); col += (alb + spec * 0.3) * max(dot(n, B * inversesqrt(max(bd, 1e-6))), 0.0) * bc * uLeds * 0.28 / (1.0 + bd * 1.9); // overhead only: a soft top light, as if the maze were a model on a bench if (uView == 2) col += alb * (0.25 + 0.75 * max(n.y, 0.0)) * vec3(0.55, 0.60, 0.70) * 0.30 * uLamp * occ; // the arc flash: no shadow, it is over in three frames if (gArcA > 0.001) { vec3 A = gArcP - p; float ad = dot(A, A); A *= inversesqrt(max(ad, 1e-6)); float andl = max(dot(n, A), 0.0); col += alb * andl * vec3(0.62, 0.80, 1.0) * gArcA * 5.0 / (1.0 + ad * 1.5); } // a floor of cold ambient so a chamber the beam has left is not pure void col += alb * vec3(0.042, 0.044, 0.050) * occ * (0.5 + 0.5 * n.y); return col; } // ---------------------------------------------------------------- volumetric vec3 beamFog(vec3 ro, vec3 rd, float t0, float t1, float jit){ vec3 acc = vec3(0.0); float span = min(t1 - t0, 18.0); float stq = span / float(VOLSTEP); for (int i = 0; i < VOLSTEP; i++) { float tt = t0 + stq * (float(i) + jit); vec3 x = ro + rd * tt; vec3 L = gLampP - x; float dd = dot(L, L); float cd = dot(-L * inversesqrt(max(dd, 1e-6)), gLampD); float cone = smoothstep(cos(uCone * 1.85), cos(uCone * 0.80), cd); // haze within a hand's width of the lens is not something a lens can see; the // nose camera rides just ahead of the lamp, where the beam is brightest, so // its fade runs much further out or the frame is nothing but lit fog float nearF = smoothstep(0.05, uView == 1 ? 2.5 : 0.9, tt); if (cone > 0.001) acc += vec3(1.0, 0.86, 0.66) * gFlick * (nearF * cone * beamOcc(x) / (1.0 + dd * 1.05)); // dust hanging in dead air, lit by nothing in particular acc += vec3(0.16, 0.15, 0.14) * nearF * 0.05 * uGrime; if (gArcA > 0.001) { float ad = dot(gArcP - x, gArcP - x); acc += vec3(0.55, 0.75, 1.0) * gArcA * 0.5 / (1.0 + ad * 2.0); } } return acc * (stq * uHaze * 0.55); } // ---------------------------------------------------------------- camera // Where the camera is and what it looks at. Walks the route, so it runs in the // state pass only. void camPoints(out vec3 ro, out vec3 tgt){ vec3 tn; if (uView == 2) { // overhead: above and behind the nose, looking down into the maze with the // roof sliced off at the worm's own level vec3 hp = pathAt(gHead, true, tn); ro = hp + vec3(0.0, 5.5 + uDist * 2.2, -(2.6 + uDist * 1.4)); tgt = hp + vec3(0.0, 0.0, 1.2); gCut = hp.y + 0.55 * uBore; } else if (uView == 1) { ro = pathAt(gHead + 0.20, true, tn); // on the weave, so it is always square in front of the nose tgt = pathAt(gHead + 2.6, false, tn); } else { // Follow: ON the route, behind the tail. The route is the one line through // this maze guaranteed to be open -- every corner, every shaft, every port // centre -- so a camera that rides it goes wherever the worm went and can // never be stopped by anything. float A = gHead - gL - (0.30 + uDist * 0.45); ro = pathAt(A, false, tn); // look along the route, never at the worm directly: aiming at the body // while it climbed a shaft pointed the camera into a wall tgt = pathAt(A + 2.4, false, tn); } } void camera(out vec3 ro, out mat3 cm){ ro = gCamRo; vec3 f = normalize(gCamTgt - ro); // World up, pitched over as the view tips into a shaft: toward -z when // climbing, +z when dropping. Blending toward +z regardless made the blended // up pass exactly through the view direction partway up a climb, and the // frame went NaN. vec3 Y = normalize(mix(vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, -sign(f.y)), smoothstep(0.55, 0.97, abs(f.y)))); vec3 r = normalize(cross(f, Y)); cm = mat3(r, cross(r, f), f); gCamP = ro; gCamD = f; } // ---------------------------------------------------------------- pass 0 vec4 renderScene(vec2 uv, vec2 res){ vec3 ro; mat3 cm; camera(ro, cm); vec2 sc2 = (uv * 2.0 - 1.0) * vec2(res.x / res.y, 1.0); vec3 rd = normalize(cm * vec3(sc2, 1.45 / uFov)); float jit = hash12(gl_FragCoord.xy + fract(TIME) * 91.0); float t = 0.02 + jit * 0.01; float tStart = 0.0; bool capHit = false; float capDepth = 0.0; if (uView == 2) { // start every ray at the cut; if it starts inside solid, it is looking at // the section face of the cut itself if (rd.y < -0.01 && ro.y > gCut) { t = (ro.y - gCut) / -rd.y; tStart = t; float m0 = map(ro + rd * t).x; if (m0 < 0.0) { capHit = true; capDepth = -m0; } } } float id = 0.0; bool hit = false; if (!capHit) { for (int i = 0; i < MAXSTEP; i++) { vec2 m = map(ro + rd * t); if (m.x < 0.0009 * t + 0.0009) { id = m.y; hit = true; break; } t += m.x * LIP; if (t > FAR) break; } } vec3 col = vec3(0.0); float dep = FAR; if (capHit) { // section poche: flat dark fill with a bright line where the cut meets air dep = t; vec3 p = ro + rd * t; col = vec3(0.085, 0.090, 0.100) * (0.85 + 0.15 * hash12(floor(p.xz * 6.0))); col += vec3(1.0, 0.42, 0.08) * 0.55 * smoothstep(0.045, 0.012, capDepth); } else if (hit) { dep = t; vec3 p = ro + rd * t; vec3 n = normalAt(p, t); vec3 alb; float rgh, mtl; vec3 emi; material(p, n, id, alb, rgh, mtl, emi); vec3 L = normalize(gLampP - p); float sh = softShadow(p + n * 0.012, L, min(length(gLampP - p), 9.0)); // no ambient occlusion: it was a fourth inlined copy of the whole maze for // an ambient term this dim col = shadePt(p, n, -rd, alb, rgh, mtl, sh, 1.0) + emi; } if (!capHit) col += beamFog(ro, rd, tStart, min(t, FAR), jit); return vec4(col, min(dep, FAR) / FAR); } // ---------------------------------------------------------------- pass 1 // Bright pass and the horizontal half of a separable blur, at two spacings so // one 11-tap pass carries both a tight halo and a wide one. vec3 bloomH(vec2 uv, vec2 res){ vec2 px = vec2(1.0 / res.x, 0.0); vec3 s = vec3(0.0); float wsum = 0.0; for (int i = -5; i <= 5; i++) { float f = float(i); float w = exp(-f * f * 0.16); vec3 a = IMG_NORM_PIXEL(sc, uv + px * (f * 1.6)).rgb; vec3 b = IMG_NORM_PIXEL(sc, uv + px * (f * 5.4)).rgb; s += (max(a - 0.75, 0.0) + max(b - 0.75, 0.0) * 0.6) * w; wsum += w * 1.6; } return s / wsum; } // ---------------------------------------------------------------- pass 2 vec3 tonemap(vec3 x){ return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0); } vec3 ramp(float t, vec3 a, vec3 b, vec3 c, vec3 d){ return a + b * cos(TAU * (c * t + d)); } vec3 finalPass(vec2 uv, vec2 res){ vec2 suv = uv; if (uStyle == 6) { // borescope: a real barrel warp vec2 c2 = uv - 0.5; suv = 0.5 + c2 * (1.0 - 0.55 * dot(c2, c2)); } vec4 s = IMG_NORM_PIXEL(sc, suv); vec3 bloom = IMG_NORM_PIXEL(bl, suv).rgb; vec3 c = (s.rgb + bloom * uBloom) * uGain; float dep = s.a; vec2 px = 1.0 / res; vec3 col; if (uStyle == 3) { // thermal: depth and radiance read as one temperature field float v = pow(clamp(lum(c) * 1.5, 0.0, 1.0), 0.42) * (1.0 - 0.35 * dep); col = clamp(ramp(v, vec3(0.42), vec3(0.46), vec3(1.0), vec3(0.00, 0.22, 0.52)) * v * 1.7 + vec3(0.02, 0.0, 0.06), 0.0, 1.0); } else if (uStyle == 4) { // phosphor: one gun, and the tube it is being drawn on float v = pow(clamp(lum(c), 0.0, 3.0), 0.68); col = vec3(0.10, 1.0, 0.42) * v; col *= 0.80 + 0.20 * sin(gl_FragCoord.y * 2.6); col += vec3(0.0, 0.045, 0.02); } else if (uStyle == 7) { // ink plate: built from structure, not from a tone curve. There is nothing // in a photograph of an unlit machine for a curve to print. float e = abs(IMG_NORM_PIXEL(sc, suv + vec2(px.x, 0.0)).a - dep) + abs(IMG_NORM_PIXEL(sc, suv + vec2(0.0, px.y)).a - dep); // the scene is lit for a dark room; paper wants it about two stops up float t = pow(clamp(lum(tonemap(c * 3.5)), 0.0, 1.0), 0.55); vec2 sp = gl_FragCoord.xy; float ink = 0.0; ink = max(ink, step(0.72, sin((sp.x + sp.y) * 0.62)) * smoothstep(0.66, 0.46, t)); ink = max(ink, step(0.72, sin((sp.x - sp.y) * 0.62)) * smoothstep(0.42, 0.24, t)); ink = max(ink, step(0.55, sin(sp.y * 0.80)) * smoothstep(0.20, 0.08, t)); ink = max(ink, smoothstep(0.06, 0.0, t)); ink = max(ink, smoothstep(0.006, 0.030, e)); col = vec3(1.0) - ink * vec3(0.93, 0.94, 0.95); col *= 0.97 + 0.03 * hash12(sp); return clamp(col, 0.0, 1.0); } else { if (uStyle == 1) c *= vec3(0.58, 0.92, 1.42); else if (uStyle == 2) c = vec3(c.r * 1.45 + c.g * 0.25, c.g * 0.80 + c.r * 0.10, c.b * 0.22); else if (uStyle == 5) c = vec3(c.r * 1.05 + c.b * 0.45, c.g * 0.42, c.b * 1.55 + c.r * 0.20); else if (uStyle == 6) c *= vec3(1.06, 1.00, 0.88); col = tonemap(c); if (uStyle == 6) col = mix(vec3(lum(col)), col, 0.55); } col = pow(col, vec3(1.0 / max(uGamma, 0.05))); vec2 vc = uv - 0.5; float vg = 1.0 - uVign * (uStyle == 6 ? 2.1 : 1.25) * dot(vc, vc); col *= clamp(vg, 0.0, 1.0); if (uStyle == 6) col *= smoothstep(0.50, 0.44, length(vc * vec2(1.0, 1.0))); col += (hash12(gl_FragCoord.xy + fract(TIME) * 311.0) - 0.5) * 0.055 * uFilm; return clamp(col, 0.0, 1.0); } // ---------------------------------------------------------------- setup void params(){ gC = uCell; gW = float(uLanes); gNF = float(uFloors); gH = vec2(1.05, 0.85) * uBore; gJ = 1.20 * uBore; gRC = 0.90 * uBore; gRP = uPort * 0.50 * uBore; gR0 = 0.19 * uGirth * uBore; gNeed = clamp(gRP * 0.72 / max(gR0, 1e-3), 0.22, 1.0); gA = 0.25 * uWeave * uBore; gSEG = uSegLen; gL = uLength; gEye = uView == 2 ? 7.0 : (uView == 0 ? 1.4 : 1.0); // a failing lamp: mostly steady, with the occasional stutter float fl = hash11(floor(TIME * 11.0)); gFlick = mix(1.0, 0.45 + 0.55 * hash11(floor(TIME * 37.0)), step(0.90, fl)) * (0.94 + 0.06 * sin(TIME * 31.0)); gCut = 1e5; } void setup(){ // ---- one period of the route: lanes, stage lengths, running distance float lx[34]; float ly[34]; float ln[32]; float pre[33]; for (int i = 0; i < 34; i++) { lx[i] = laneX(float(i)); ly[i] = laneY(float(i)); } pre[0] = 0.0; for (int i = 0; i < 32; i++) { float dx = abs(lx[i + 1] - lx[i]), dy = abs(ly[i + 1] - ly[i]); float hx = step(0.5, dx), hy = step(0.5, dy); float k = 2.0 * hx + 2.0 * hy - hx * hy; // corners in this stage float cn = max(step(0.5, abs(lx[i + 2] - lx[i + 1])), step(0.5, abs(ly[i + 2] - ly[i + 1]))); ln[i] = gC * (1.0 + dx + dy) - gRC * cn + step(0.5, k) * (k * gRC * (PI * 0.5 - 2.0) + gRC); pre[i + 1] = pre[i] + ln[i]; } float total = pre[32]; // ---- where the nose is gHead = TIME * uSpeed * 1.9 + 120.0; // +120 puts glslop's t=0.8 poster on the worm bending up out of a port float cyc = floor(gHead / total); float hm = gHead - cyc * total; float kk = 0.0, puH = 0.0; for (int i = 0; i < 32; i++) { if (hm >= pre[i]) { kk = float(i); puH = pre[i]; } } float sH = cyc * 32.0 + kk; gSBase = sH - 6.0; // ---- the eight stages around it (six behind, one ahead), flattened float u = cyc * total + puH; for (int i = 0; i < 6; i++) u -= stageLen(sH - 6.0 + float(i)); gBMin = vec3(1e5); gBMax = vec3(-1e5); float arcL = gRC * PI * 0.5; vec3 ez = vec3(0.0, 0.0, 1.0); for (int i = 0; i < 8; i++) { float s = sH - 6.0 + float(i); float x0 = laneX(s), x1 = laneX(s + 1.0), x2 = laneX(s + 2.0); float y0 = laneY(s), y1 = laneY(s + 1.0), y2 = laneY(s + 2.0); float dx = x1 - x0, dy = y1 - y0; float hx = step(0.5, abs(dx)), hy = step(0.5, abs(dy)), hk = max(hx, hy); float cn = max(step(0.5, abs(x2 - x1)), step(0.5, abs(y2 - y1))); vec3 ex = vec3(sign(dx), 0.0, 0.0), ey = vec3(0.0, sign(dy), 0.0); vec3 P0 = vec3(x0 * gC, y0 * gC, s * gC); vec3 P1 = P0 + ex * abs(dx) * gC; vec3 P2 = P1 + ey * abs(dy) * gC; float ust = u; gSu0[i] = ust; gEK[i*6] = hk * 2.0; gES[i*6] = P0; gEA[i*6] = ez; gEB[i*6] = hx > 0.5 ? ex : ey; gEL[i*6] = hk * arcL; gEU[i*6] = u; u += gEL[i*6]; gEK[i*6+1] = hx; gES[i*6+1] = P0 + ex * gRC; gEA[i*6+1] = ex; gEB[i*6+1] = ex; gEL[i*6+1] = hx * (abs(dx) * gC - 2.0 * gRC); gEU[i*6+1] = u; u += gEL[i*6+1]; gEK[i*6+2] = hx * 2.0; gES[i*6+2] = P1; gEA[i*6+2] = ex; gEB[i*6+2] = hy > 0.5 ? ey : ez; gEL[i*6+2] = hx * arcL; gEU[i*6+2] = u; u += gEL[i*6+2]; gEK[i*6+3] = hy; gES[i*6+3] = P1 + ey * gRC; gEA[i*6+3] = ey; gEB[i*6+3] = ey; gEL[i*6+3] = hy * (abs(dy) * gC - 2.0 * gRC); gEU[i*6+3] = u; u += gEL[i*6+3]; gEK[i*6+4] = hy * 2.0; gES[i*6+4] = P2; gEA[i*6+4] = ey; gEB[i*6+4] = ez; gEL[i*6+4] = hy * arcL; gEU[i*6+4] = u; u += gEL[i*6+4]; float t0 = hk * gRC; gEK[i*6+5] = 1.0; gES[i*6+5] = P2 + ez * t0; gEA[i*6+5] = ez; gEB[i*6+5] = ez; gEL[i*6+5] = gC - t0 - cn * gRC; gEU[i*6+5] = u; u += gEL[i*6+5]; if (ust < gHead + 0.5 && u > gHead - gL - 0.5) { vec3 b = P2 + ez * gC; gBMin = min(gBMin, min(P0, min(P1, b))); gBMax = max(gBMax, max(P0, max(P1, b))); } } gBMin -= vec3(0.9); gBMax += vec3(0.9); // ---- lights that ride the route vec3 tn; gLampP = pathAt(gHead - 0.05, true, tn); gLampD = tn; gLampN = floor(gLampP / gC + 0.5); gBL0 = pathAt(gHead - min(1.2, gL * 0.3), true, tn); gBL1 = pathAt(gHead - gL * 0.5, true, tn); gBL2 = pathAt(gHead - gL * 0.8, true, tn); // ---- a short in a loom somewhere near the nose float ci = floor(gHead / 2.1 + 0.5); float hh = hash11(ci * 3.13 + 5.0); float ph = fract(TIME * 0.5 + hh * 7.0); gArcA = uSpark * smoothstep(0.0, 0.015, ph) * smoothstep(0.14, 0.02, ph) * (0.45 + 0.55 * abs(sin(TIME * 79.0 + hh * 20.0))); vec3 ap = pathAt(gHead + 0.6 + hh * 1.2, false, tn); vec3 side = perpOf(tn); vec3 up = cross(tn, side); gArcP = ap + side * (gH.x - 0.21) * sign(hh - 0.5) + up * (gH.y - 0.20) * sign(fract(hh * 11.0) - 0.5); camPoints(gCamRo, gCamTgt); } // ---------------------------------------------------------------- state vec4 packState(float i){ vec3 base = vec3(0.0, 0.0, gSBase * gC); vec4 ua = vec4(gSu0[0], gSu0[1], gSu0[2], gSu0[3]) - gHead; vec4 ub = vec4(gSu0[4], gSu0[5], gSu0[6], gSu0[7]) - gHead; if (i < 0.5) return vec4(mod(gSBase, 512.0), floor(gSBase / 512.0), gArcA, min(gCut, 6.0e4)); if (i < 1.5) return floor(ua); if (i < 2.5) return fract(ua); if (i < 3.5) return floor(ub); if (i < 4.5) return fract(ub); if (i < 5.5) return vec4(floor(gLampP - base), 0.0); if (i < 6.5) return vec4(fract(gLampP - base), 0.0); if (i < 7.5) return vec4(gLampD, 0.0); if (i < 8.5) return vec4(floor(gBL0 - base), 0.0); if (i < 9.5) return vec4(fract(gBL0 - base), 0.0); if (i < 10.5) return vec4(floor(gBL1 - base), 0.0); if (i < 11.5) return vec4(fract(gBL1 - base), 0.0); if (i < 12.5) return vec4(floor(gBL2 - base), 0.0); if (i < 13.5) return vec4(fract(gBL2 - base), 0.0); if (i < 14.5) return vec4(floor(gArcP - base), 0.0); if (i < 15.5) return vec4(fract(gArcP - base), 0.0); if (i < 16.5) return vec4(floor(gCamRo - base), 0.0); if (i < 17.5) return vec4(fract(gCamRo - base), 0.0); if (i < 18.5) return vec4(floor(gCamTgt - base), 0.0); if (i < 19.5) return vec4(fract(gCamTgt - base), 0.0); if (i < 20.5) return vec4(clamp(gBMin - base, -6.0e4, 6.0e4), 0.0); return vec4(clamp(gBMax - base, -6.0e4, 6.0e4), 0.0); } vec4 stx(float i){ return IMG_PIXEL(st, vec2(i + 0.5, 0.5)); } vec3 stp(float i){ return stx(i).xyz + stx(i + 1.0).xyz; } // Everything the scene pass needs from the route, read back. Route distances // come back relative to the nose, so the nose is at 0 from here on. void loadState(){ vec4 t0 = stx(0.0); gSBase = t0.x + t0.y * 512.0; gArcA = t0.z; gCut = t0.w; vec3 base = vec3(0.0, 0.0, gSBase * gC); vec4 ua = stx(1.0) + stx(2.0); vec4 ub = stx(3.0) + stx(4.0); gSu0[0] = ua.x; gSu0[1] = ua.y; gSu0[2] = ua.z; gSu0[3] = ua.w; gSu0[4] = ub.x; gSu0[5] = ub.y; gSu0[6] = ub.z; gSu0[7] = ub.w; gHead = 0.0; gLampP = base + stp(5.0); gLampD = normalize(stx(7.0).xyz + vec3(0.0, 0.0, 1e-5)); gLampN = floor(gLampP / gC + 0.5); gBL0 = base + stp(8.0); gBL1 = base + stp(10.0); gBL2 = base + stp(12.0); gArcP = base + stp(14.0); gCamRo = base + stp(16.0); gCamTgt = base + stp(18.0); gBMin = base + stx(20.0).xyz - vec3(0.1); gBMax = base + stx(21.0).xyz + vec3(0.1); } // ---------------------------------------------------------------- dispatch void main(){ vec2 uv = gl_FragCoord.xy / RENDERSIZE.xy; if (PASSINDEX == 0) { // the route, once per frame: only a row of 22 texels does any work if (gl_FragCoord.x < 22.0 && gl_FragCoord.y < 1.0) { params(); setup(); gl_FragColor = packState(floor(gl_FragCoord.x)); } else { gl_FragColor = vec4(0.0); } } else if (PASSINDEX == 1) { params(); loadState(); gl_FragColor = renderScene(uv, RENDERSIZE.xy); } else if (PASSINDEX == 2) { gl_FragColor = vec4(bloomH(uv, RENDERSIZE.xy), 1.0); } else { gl_FragColor = vec4(finalPass(uv, RENDERSIZE.xy), 1.0); } }
A segmented industrial worm machine picking its way through a derelict maze inside a dead machine. The maze is a lattice of junction chambers joined by square ducts, several lanes wide and up to three floors deep: the route turns left and right and climbs and drops through shafts, and every other duct is opened or sealed by a hash, which is what makes the side passages, loops and dead ends. Many ducts have a bulkhead halfway along with a small bolted PORT, and the worm compresses exactly as much as the hole demands to squeeze through, anchor FINS folding as it goes. The worm is built rather than grown: faceted plate segments with real gaps, an exposed drive shaft bridging them, a dorsal rail, radii that step down per segment, a machined nose plate with a stuttering headlamp, and a faceted stinger spike for a tail with a red beacon ring at its root. The place is filthy -- rust streaks, soot in the corners, dust on every up-facing surface, burnt-out chambers, dead indicator panels and a few sick survivors, corroded boards and decades-old wiring -- all of it under GRIME. Four passes: route state, scene, bloom, grade. Cameras: follow (rides the route behind the worm), head, overhead (the maze from above with the roof cut away). ARMOR: brushed steel, black anodized, copper, bone ceramic, hazard yellow, chrome, oxide red, carbon weave. STYLE: service light, cold diagnostic, amber fault, thermal, phosphor, ultraviolet, borescope, ink plate. Try LANES and FLOORS at maximum with BRANCH high for a labyrinth.
export clip · render a video in your browser
Renders to video in your browser (no upload), stepping the real renderer frame by frame so multipass + feedback come out right. motion auto-animates the shader's own knobs — each export rolls a fresh take (🎲 re-roll, 🔒 to pin one you like). GIF is slower with a tighter length cap; MP4/WebM are faster. Some devices record in real time (noted below if so) — keep the tab visible.
embed · drop this shader into any page
Renders client-side in the reader's browser (CC0 — no attribution required, but the backlink is appreciated).