Back to shaders

Shader test bench

20260608

glsl-daily-practice generative glsl runnable fragment MIT
Source
runnable fragment

Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.

Code

precision mediump float;
#define TDOutputSwizzle(c) (c)
// ===============================================================
// ODARAIA NEON FOSSIL
// TouchDesigner GLSL TOP fragment shader
// Isoxys-inspired shield carapace + cardinal spines + stalked eyes
// + grasping appendages + biramous paddles, using the original neon palette.
// ===============================================================

#define fragColor gl_FragColor
uniform float iTime;

#define MAX_STEPS 136
#define MAX_DIST  15.0
#define SURF_DIST 0.0011
#define PI        3.14159265359
#define TAU       6.28318530718

const vec3 ACID   = vec3(0.0,  1.0,  0.624);
const vec3 CYAN   = vec3(0.0,  0.812,1.0);
const vec3 VIOLET = vec3(0.545,0.0,  1.0);
const vec3 PINK   = vec3(1.0,  0.0,  0.431);

mat2 rot(float a) {
  float s = sin(a);
  float c = cos(a);
  return mat2(c, -s, s, c);
}

float hash11(float n) {
  return fract(sin(n * 12.9898) * 43758.5453123);
}

float hash13(vec3 p) {
  return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453123);
}

float noise3(vec3 x) {
  vec3 p = floor(x);
  vec3 f = fract(x);
  f = f * f * (3.0 - 2.0 * f);

  return mix(
    mix(
      mix(hash13(p + vec3(0, 0, 0)), hash13(p + vec3(1, 0, 0)), f.x),
      mix(hash13(p + vec3(0, 1, 0)), hash13(p + vec3(1, 1, 0)), f.x),
      f.y
    ),
    mix(
      mix(hash13(p + vec3(0, 0, 1)), hash13(p + vec3(1, 0, 1)), f.x),
      mix(hash13(p + vec3(0, 1, 1)), hash13(p + vec3(1, 1, 1)), f.x),
      f.y
    ),
    f.z
  );
}

float fbm(vec3 p) {
  float v = 0.0;
  float a = 0.5;
  for (int i = 0; i < 5; i++) {
    v += a * noise3(p);
    p = p * 2.04 + vec3(17.3, 9.1, 5.7);
    a *= 0.52;
  }
  return v;
}

float sdSphere(vec3 p, float r) {
  return length(p) - r;
}

float sdEllipsoid(vec3 p, vec3 r) {
  float k0 = length(p / r);
  float k1 = length(p / (r * r));
  return k0 * (k0 - 1.0) / k1;
}

float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
  vec3 pa = p - a;
  vec3 ba = b - a;
  float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
  return length(pa - ba * h) - r;
}

float sdBox(vec3 p, vec3 b) {
  vec3 q = abs(p) - b;
  return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}

float sdTriPrism(vec3 p, vec2 h) {
  vec3 q = abs(p);
  return max(q.z - h.y, max(q.x * 0.866025 + p.y * 0.5, -p.y) - h.x * 0.5);
}

float smin(float a, float b, float k) {
  float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
  return mix(b, a, h) - k * h * (1.0 - h);
}

struct Hit {
  float d;
  float m;
};

Hit opUnion(Hit a, Hit b) {
  return a.d < b.d ? a : b;
}

Hit opSmoothUnion(Hit a, Hit b, float k) {
  float d = smin(a.d, b.d, k);
  float h = smoothstep(-k, k, b.d - a.d);
  return Hit(d, mix(b.m, a.m, h));
}

float sdTaperedCapsule(vec3 p, vec3 a, vec3 b, float ra, float rb) {
  vec3 pa = p - a;
  vec3 ba = b - a;
  float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
  return length(pa - ba * h) - mix(ra, rb, h);
}

vec3 isoxysPose(vec3 p, float t) {
  p.yz *= rot(PI * 0.5);
  p.xy *= rot(-0.08);
  p.yz *= rot(0.10 + 0.025 * sin(t * 0.18));
  p.x += sin(t * 0.34) * 0.030;
  return p;
}

vec3 isoxysUnpose(vec3 q, float t) {
  q.x -= sin(t * 0.34) * 0.030;
  q.yz *= rot(-(0.10 + 0.025 * sin(t * 0.18)));
  q.xy *= rot(0.08);
  q.yz *= rot(-PI * 0.5);
  q += vec3(0.0, 0.08 * sin(t * 0.22), 0.0);
  return q;
}

float trunkWidth(float y) {
  float u = clamp((y + 0.72) / 1.74, 0.0, 1.0);
  return mix(0.18, 0.095, pow(u, 1.35)) * smoothstep(0.0, 0.08, u);
}

vec3 segmentCenter(float y, float t) {
  float u = clamp((y + 0.72) / 1.74, 0.0, 1.0);
  return vec3(
    sin(y * 2.4 - t * 0.30) * 0.015 * smoothstep(0.12, 1.0, u),
    y,
    -0.165 + cos(y * 2.1 - t * 0.25) * 0.010
  );
}

float carapaceSDF(vec3 q, float t) {
  float d = 20.0;

  for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
    float side = sideIndex == 0 ? -1.0 : 1.0;
    vec3 c = q - vec3(side * 0.155, 0.04, 0.020);
    c.xy *= rot(side * 0.055);
    c.yz *= rot(side * -0.020);

    float shield = sdEllipsoid(c, vec3(0.245, 1.08, 0.760));
    float frontWall = q.y + 1.02 + side * q.x * 0.035;
    float rearWall = 1.14 - q.y + side * q.x * 0.020;
    shield = max(shield, -frontWall);
    shield = max(shield, -rearWall);

    float ventralOpen = -q.z - 0.455 + 0.040 * cos(q.y * 2.7);
    shield = max(shield, ventralOpen);

    float valveGap = 0.020 - abs(q.x);
    shield = max(shield, valveGap);
    d = min(d, shield);
  }

  float seam = sdCapsule(q, vec3(0.0, -0.98, 0.620), vec3(0.0, 1.12, 0.600), 0.013);
  d = min(d, seam);

  for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
    float side = sideIndex == 0 ? -1.0 : 1.0;
    d = min(d, sdCapsule(q, vec3(side * 0.030, -0.98, 0.548), vec3(side * 0.245, -0.83, 0.360), 0.014));
    d = min(d, sdCapsule(q, vec3(side * 0.235, -0.80, -0.435), vec3(side * 0.255, 0.90, -0.425), 0.014));
  }

  return d;
}

float cardinalSpineSDF(vec3 q, float t) {
  float d = 20.0;
  vec3 a0 = vec3(0.0, -0.92, 0.585);
  vec3 a1 = vec3(0.0, -1.18, 0.705);
  vec3 a2 = vec3(0.0, -1.56, 0.760 + 0.018 * sin(t * 0.25));
  d = smin(d, sdTaperedCapsule(q, a0, a1, 0.075, 0.046), 0.035);
  d = smin(d, sdTaperedCapsule(q, a1, a2, 0.048, 0.010), 0.022);

  vec3 p0 = vec3(0.0, 1.03, 0.570);
  vec3 p1 = vec3(0.0, 1.38, 0.640);
  vec3 p2 = vec3(0.0, 1.86, 0.635 + 0.012 * sin(t * 0.19 + 1.6));
  d = smin(d, sdTaperedCapsule(q, p0, p1, 0.082, 0.050), 0.038);
  d = smin(d, sdTaperedCapsule(q, p1, p2, 0.052, 0.012), 0.022);
  return d;
}

float headSDF(vec3 q, float t) {
  float d = sdEllipsoid(q - vec3(0.0, -0.92, -0.150), vec3(0.200, 0.135, 0.105));

  for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
    float side = sideIndex == 0 ? -1.0 : 1.0;
    float bob = 0.018 * sin(t * 0.46 + side * 0.7);
    vec3 root = vec3(side * 0.095, -0.96, -0.085);
    vec3 tip = vec3(side * 0.285, -1.18, -0.040 + bob);
    d = smin(d, sdTaperedCapsule(q, root, tip, 0.032, 0.050), 0.022);
    d = smin(d, sdSphere(q - tip, 0.185), 0.036);
  }

  return d;
}

float frontalAppendageSDF(vec3 q, float t) {
  float d = 20.0;

  for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
    float side = sideIndex == 0 ? -1.0 : 1.0;
    vec3 prev = vec3(side * 0.105, -1.03, -0.205);

    for (int i = 0; i < 7; i++) {
      float fi = float(i);
      float u = fi / 6.0;
      float flex = sin(t * 0.72 - fi * 0.55 + side * 0.35) * 0.040;
      vec3 next = vec3(
        side * (0.150 + 0.235 * sin(u * 1.45) - 0.035 * u),
        -1.08 - 0.145 * fi + 0.030 * sin(u * PI + flex),
        -0.245 + 0.105 * fi - 0.046 * fi * fi + flex
      );

      float pod = sdTaperedCapsule(q, prev, next, 0.034 - u * 0.010, 0.030 - u * 0.012);
      d = smin(d, pod, 0.010);
      d = smin(d, sdEllipsoid(q - next, vec3(0.040 - u * 0.010, 0.026, 0.030)), 0.010);

      vec3 inner = mix(prev, next, 0.62);
      vec3 spineTip = inner + vec3(-side * (0.070 + 0.020 * u), -0.020, 0.035 + 0.020 * u);
      d = smin(d, sdTaperedCapsule(q, inner, spineTip, 0.010, 0.0025), 0.004);
      prev = next;
    }

    vec3 clawA = prev;
    vec3 clawB = prev + vec3(-side * 0.080, -0.060, 0.100);
    vec3 clawC = prev + vec3(-side * 0.145, 0.010, 0.160);
    d = smin(d, sdTaperedCapsule(q, clawA, clawB, 0.022, 0.014), 0.008);
    d = smin(d, sdTaperedCapsule(q, clawB, clawC, 0.014, 0.003), 0.006);
  }

  return d;
}

float trunkSDF(vec3 q, float t) {
  float d = 20.0;

  for (int i = 0; i < 13; i++) {
    float fi = float(i);
    float u = fi / 12.0;
    float y = mix(-0.66, 0.98, u);
    vec3 c = segmentCenter(y, t);
    float w = trunkWidth(y);
    float seg = sdEllipsoid(q - c, vec3(w, 0.043, 0.105));
    d = smin(d, seg, 0.018);
  }

  float gut = sdCapsule(q, segmentCenter(-0.60, t) + vec3(0.0, 0.0, 0.010), segmentCenter(1.08, t) + vec3(0.0, 0.0, 0.005), 0.023);
  d = smin(d, gut, 0.018);

  return d;
}

float limbSDF(vec3 q, float t) {
  float d = 20.0;

  for (int i = 0; i < 13; i++) {
    float fi = float(i);
    float u = fi / 12.0;
    float y = mix(-0.58, 0.92, u);
    float w = trunkWidth(y);
    vec3 c = segmentCenter(y, t);

    for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
      float side = sideIndex == 0 ? -1.0 : 1.0;
      float beat = sin(t * 1.36 - fi * 0.48 + side * 0.30);
      float scale = mix(1.0, 0.52, u);
      vec3 root = c + vec3(side * w * 0.82, 0.0, -0.050);
      vec3 endo = root + vec3(side * 0.160 * scale, 0.018 * beat, -0.120 - 0.035 * beat);
      vec3 exoCenter = root + vec3(side * 0.270 * scale, 0.028 * beat, -0.190 - 0.045 * beat);
      vec3 exo = q - exoCenter;
      exo.xy *= rot(side * (0.30 + 0.12 * beat));
      float paddle = sdEllipsoid(exo, vec3(0.145 * scale, 0.040, 0.038));

      d = smin(d, sdTaperedCapsule(q, root, endo, 0.012, 0.006), 0.006);
      d = smin(d, paddle, 0.010);

      for (int j = 0; j < 5; j++) {
        float fj = float(j);
        float su = (fj + 0.5) / 5.0;
        vec3 br = exoCenter + vec3(side * (0.040 + 0.095 * scale), (su - 0.5) * 0.092, -0.010);
        vec3 bt = br + vec3(side * 0.075 * scale, 0.012 * sin(t + fi + fj), 0.055 + 0.010 * fj);
        d = smin(d, sdCapsule(q, br, bt, 0.0032), 0.003);
      }
    }
  }

  return d;
}

float tailSDF(vec3 q, float t) {
  float d = 20.0;
  vec3 root = segmentCenter(1.02, t);
  vec3 flap = q - root - vec3(0.0, 0.205, -0.025 + 0.018 * sin(t * 0.48));
  flap.yz *= rot(-0.16 + 0.035 * sin(t * 0.42));
  d = smin(d, sdEllipsoid(flap, vec3(0.105, 0.175, 0.032)), 0.018);
  d = smin(d, sdTaperedCapsule(q, root, root + vec3(0.0, 0.270, -0.025), 0.040, 0.018), 0.016);

  return d;
}

Hit mapScene(vec3 p, float t) {
  p -= vec3(0.0, 0.08 * sin(t * 0.22), 0.0);
  vec3 q = isoxysPose(p, t);

  Hit res = Hit(20.0, 0.0);
  res = opSmoothUnion(res, Hit(carapaceSDF(q, t), 1.0), 0.040);
  res = opSmoothUnion(res, Hit(headSDF(q, t), 2.0), 0.035);
  res = opSmoothUnion(res, Hit(trunkSDF(q, t), 3.0), 0.030);
  res = opSmoothUnion(res, Hit(limbSDF(q, t), 4.0), 0.014);
  res = opSmoothUnion(res, Hit(frontalAppendageSDF(q, t), 5.0), 0.012);
  res = opSmoothUnion(res, Hit(cardinalSpineSDF(q, t), 6.0), 0.026);
  res = opSmoothUnion(res, Hit(tailSDF(q, t), 6.0), 0.028);

  float texture = (fbm(q * 7.2 + vec3(0.0, t * 0.10, 0.0)) - 0.5) * 0.006;
  res.d += texture;
  return res;
}

float rayMarch(vec3 ro, vec3 rd, float t, out float glow, out float mat) {
  float d = 0.0;
  glow = 0.0;
  mat = 0.0;

  for (int i = 0; i < MAX_STEPS; i++) {
    vec3 p = ro + rd * d;
    Hit h = mapScene(p, t);
    glow += 0.013 / (0.014 + h.d * h.d * 38.0);

    if (h.d < SURF_DIST || d > MAX_DIST) {
      mat = h.m;
      break;
    }

    d += max(h.d * 0.58, 0.0035);
  }

  return d;
}

vec3 getNormal(vec3 p, float t) {
  vec2 e = vec2(0.002, 0.0);
  return normalize(vec3(
    mapScene(p + e.xyy, t).d - mapScene(p - e.xyy, t).d,
    mapScene(p + e.yxy, t).d - mapScene(p - e.yxy, t).d,
    mapScene(p + e.yyx, t).d - mapScene(p - e.yyx, t).d
  ));
}

vec3 palette(float x) {
  vec3 a = mix(ACID, CYAN, smoothstep(0.00, 0.38, x));
  vec3 b = mix(VIOLET, PINK, smoothstep(0.46, 1.00, x));
  return mix(a, b, smoothstep(0.24, 0.94, x));
}

vec3 materialColor(float mat, vec3 p, vec3 n, vec3 rd, float t) {
  float fres = pow(1.0 - max(dot(n, -rd), 0.0), 2.1);
  float bands = 0.5 + 0.5 * sin(p.y * 30.0 + p.x * 9.0 - t * 1.2);
  vec3 col = CYAN;

  if (mat < 1.5) {
    col = mix(CYAN, VIOLET, 0.42 + fres * 0.38);
    col += ACID * pow(bands, 10.0) * 0.20;
  } else if (mat < 2.5) {
    col = mix(ACID, CYAN, 0.35 + fres * 0.30);
    col += PINK * fres * 0.25;
  } else if (mat < 3.5) {
    col = mix(CYAN, VIOLET, 0.28 + bands * 0.35);
  } else if (mat < 4.5) {
    col = mix(ACID, CYAN, 0.48) + PINK * fres * 0.50;
  } else if (mat < 5.5) {
    col = mix(ACID, PINK, 0.24 + bands * 0.28);
  } else {
    col = mix(PINK, VIOLET, 0.36 + fres * 0.50);
  }

  col += mix(CYAN, ACID, 0.45) * fres * 0.65;
  return col;
}

float distSeg(vec2 p, vec2 a, vec2 b) {
  vec2 pa = p - a;
  vec2 ba = b - a;
  float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
  return length(pa - ba * h);
}

vec2 projectPoint(vec3 p, vec3 ro, vec3 uu, vec3 vv, vec3 ww) {
  vec3 rel = p - ro;
  float z = max(dot(rel, ww), 0.05);
  return vec2(dot(rel, uu), dot(rel, vv)) / z;
}

vec3 lineOverlay(vec2 st, vec3 ro, vec3 uu, vec3 vv, vec3 ww, float t) {
  vec3 col = vec3(0.0);

  for (int i = 0; i < 13; i++) {
    float fi = float(i);
    float u = fi / 12.0;
    float y = mix(-0.92, 1.08, u);
    float h = sqrt(max(0.0, 1.0 - pow((y - 0.04) / 1.10, 2.0)));
    float w = 0.245 * h;
    vec3 a = isoxysUnpose(vec3(-w, y, 0.590 * h - 0.045), t);
    vec3 b = isoxysUnpose(vec3(w, y, 0.590 * h - 0.045), t);
    float d = distSeg(st, projectPoint(a, ro, uu, vv, ww), projectPoint(b, ro, uu, vv, ww));
    col += mix(ACID, CYAN, u) * (exp(-d * 145.0) * 0.034 + smoothstep(0.0014, 0.0, d) * 0.055);
  }

  for (int i = 0; i < 13; i++) {
    float fi = float(i);
    float u = fi / 12.0;
    float y = mix(-0.58, 0.92, u);
    float w = trunkWidth(y);
    for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
      float side = sideIndex == 0 ? -1.0 : 1.0;
      vec3 c = segmentCenter(y, t);
      float beat = sin(t * 1.36 - fi * 0.48 + side * 0.30);
      float scale = mix(1.0, 0.52, u);
      vec3 a = isoxysUnpose(c + vec3(side * w * 0.82, 0.0, -0.050), t);
      vec3 b = isoxysUnpose(c + vec3(side * (w + 0.300 * scale), 0.028 * beat, -0.220 - 0.045 * beat), t);
      float d = distSeg(st, projectPoint(a, ro, uu, vv, ww), projectPoint(b, ro, uu, vv, ww));
      col += mix(CYAN, VIOLET, u * 0.65) * exp(-d * 96.0) * 0.030;
    }
  }

  for (int i = 0; i < 7; i++) {
    float fi = float(i);
    float u = fi / 6.0;
    for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
      float side = sideIndex == 0 ? -1.0 : 1.0;
      float flex = sin(t * 0.72 - fi * 0.55 + side * 0.35) * 0.040;
      vec3 a = vec3(
        side * (0.150 + 0.235 * sin(max(0.0, u - 0.16) * 1.45) - 0.035 * max(0.0, u - 0.16)),
        -1.08 - 0.145 * max(0.0, fi - 1.0) + 0.030 * sin(max(0.0, u - 0.16) * PI + flex),
        -0.245 + 0.105 * max(0.0, fi - 1.0) - 0.046 * max(0.0, fi - 1.0) * max(0.0, fi - 1.0) + flex
      );
      vec3 b = vec3(
        side * (0.150 + 0.235 * sin(u * 1.45) - 0.035 * u),
        -1.08 - 0.145 * fi + 0.030 * sin(u * PI + flex),
        -0.245 + 0.105 * fi - 0.046 * fi * fi + flex
      );
      a = isoxysUnpose(a, t);
      b = isoxysUnpose(b, t);
      float d = distSeg(st, projectPoint(a, ro, uu, vv, ww), projectPoint(b, ro, uu, vv, ww));
      col += mix(CYAN, VIOLET, u * 0.65) * exp(-d * 96.0) * 0.030;
    }
  }

  for (int sideIndex = 0; sideIndex < 2; sideIndex++) {
    float side = sideIndex == 0 ? -1.0 : 1.0;
    vec3 root = isoxysUnpose(vec3(side * 0.095, -0.96, -0.085), t);
    vec3 eye = isoxysUnpose(vec3(side * 0.285, -1.18, -0.040), t);
    vec2 er = projectPoint(root, ro, uu, vv, ww);
    vec2 ee = projectPoint(eye, ro, uu, vv, ww);
    float stalk = distSeg(st, er, ee);
    float eyeGlow = length(st - ee);
    col += mix(ACID, CYAN, 0.28) * exp(-stalk * 95.0) * 0.080;
    col += mix(CYAN, PINK, 0.38) * exp(-eyeGlow * 44.0) * 0.170;
    col += ACID * exp(-eyeGlow * 140.0) * 0.120;
  }

  return col;
}

vec3 background(vec2 st, float t) {
  vec3 col = mix(vec3(0.002, 0.006, 0.022), vec3(0.010, 0.045, 0.095), smoothstep(-1.0, 1.0, st.y));

  float caustic = 0.0;
  vec2 q = st;
  for (int i = 0; i < 5; i++) {
    float fi = float(i);
    q += 0.20 * vec2(cos(t * 0.16 + fi), sin(t * 0.12 + fi * 1.7));
    caustic += sin(q.x * (3.0 + fi) + t * 0.33) * cos(q.y * (3.6 + fi) - t * 0.26);
  }
  col += mix(CYAN, VIOLET, 0.38) * pow(0.5 + 0.5 * caustic / 5.0, 4.0) * 0.15;

  for (int i = 0; i < 70; i++) {
    float fi = float(i);
    vec2 p = vec2(hash11(fi * 13.7), hash11(fi * 41.2)) * 2.0 - 1.0;
    p.y = fract(p.y * 0.5 + 0.5 + t * (0.012 + hash11(fi) * 0.025)) * 2.2 - 1.1;
    p.x += sin(t * 0.10 + fi) * 0.055;
    float d = length(st - p);
    col += palette(hash11(fi * 4.9)) * exp(-d * 90.0) * (0.014 + 0.032 * hash11(fi * 2.1));
  }

  return col;
}

void main() {
  vec2 uv = vUV.st;
  vec2 st = uv * 2.0 - 1.0;
  st.x *= uTDOutputInfo.res.z / uTDOutputInfo.res.w;

  float t = iTime;

  float cycle = 0.5 + 0.5 * sin(t * 0.16);
  float track = smoothstep(0.28, 0.92, cycle);
  vec3 headTarget = isoxysUnpose(vec3(0.0, -1.12, -0.080), t);
  vec3 midTarget = isoxysUnpose(vec3(0.0, 0.04, 0.030), t);
  vec3 tailTarget = isoxysUnpose(vec3(0.0, 1.44, 0.545), t);
  vec3 target = mix(headTarget, midTarget, track);
  float tailReveal = smoothstep(0.68, 0.96, track);
  target = mix(target, tailTarget, tailReveal * 0.48);

  float orbit = -0.88 + sin(t * 0.12) * 0.26 + tailReveal * 0.34;
  float camDist = 4.05 + tailReveal * 0.74 + 0.18 * sin(t * 0.11 + 1.2);
  vec3 ro = target + vec3(
    sin(orbit) * camDist,
    0.54 + tailReveal * 0.28 + sin(t * 0.17) * 0.18,
    cos(orbit) * camDist
  );
  vec3 ww = normalize(target - ro);
  vec3 uu = normalize(cross(vec3(0.0, 1.0, 0.0), ww));
  vec3 vv = cross(ww, uu);
  float lens = mix(1.42, 1.74, tailReveal);
  vec3 rd = normalize(uu * st.x * 0.96 + vv * st.y + ww * lens);

  vec3 col = background(st, t);

  float glow;
  float mat;
  float d = rayMarch(ro, rd, t, glow, mat);

  if (d < MAX_DIST) {
    vec3 p = ro + rd * d;
    vec3 n = getNormal(p, t);

    vec3 l1 = normalize(vec3(-0.45, 0.82, -0.25));
    vec3 l2 = normalize(vec3(0.58, -0.12, 0.72));
    float diff = max(dot(n, l1), 0.0);
    float back = pow(max(dot(l2, rd), 0.0), 2.0);
    float rim = pow(1.0 - max(dot(n, -rd), 0.0), 2.5);

    vec3 body = materialColor(mat, p, n, rd, t);
    vec3 lit = body * (0.26 + diff * 0.72);
    lit += ACID * back * 0.28;
    lit += mix(VIOLET, PINK, 0.48) * rim * 1.10;

    vec3 h = normalize(l1 - rd);
    float spec = pow(max(dot(n, h), 0.0), 68.0);
    lit += mix(CYAN, ACID, 0.42) * spec * 1.75;

    float fog = 1.0 - exp(-d * 0.16);
    col = mix(lit, col, fog * 0.42);
  }

  col += lineOverlay(st, ro, uu, vv, ww, t) * (1.05 + 0.08 * sin(t));
  col += palette(0.42 + 0.22 * sin(t * 0.36)) * glow * 0.105;

  vec2 halo = st;
  halo.y += 0.05;
  float ring = exp(-abs(length(halo) - 0.72) * 28.0);
  col += mix(CYAN, VIOLET, 0.50) * ring * 0.045;
  col += PINK * pow(max(0.0, 1.0 - length(st * vec2(0.72, 1.0))), 4.4) * 0.075;

  col *= 1.78 + 0.13 * sin(t * 1.0);
  col += pow(max(col, 0.0), vec3(1.32)) * 0.34;

  float vignette = 1.0 - 0.20 * smoothstep(0.35, 1.60, length(st));
  col *= vignette;

  col = col / (0.82 + col);
  col = pow(max(col, 0.0), vec3(0.94));

  float grain = (hash11(uv.x * 1234.5 + uv.y * 987.6 + t) - 0.5) * 0.014;
  col += grain;

  fragColor = TDOutputSwizzle(vec4(col, 1.0));
}