Noisy Cells

An audio-reactive noise-based cells grid with color hue shifting and some light shafts.

Created by marcogomez on Mon, 27 Sep 2021 06:28:06 GMT.


// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm3Texture;
uniform vec2 resolution;

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec4 prgm3 = texture2D(prgm3Texture, uv);
  gl_FragColor = prgm3;
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D fftTexture;
uniform vec2 resolution;
uniform float time;
uniform float fft;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float bgWaveSpeed = 1.0;
const float xDistMag = 0.021;
const float yDistMag = 0.012;
const float xSineCycles = TAU;
const float ySineCycles = TAU;

vec3 hue(vec3 col, float a) {
  const vec3 k = vec3(0.57735, 0.57735, 0.57735);
  float c = cos(a);
  return col * c + cross(k, col) * sin(a) + k * dot(k, col) * (1.0 - c);
}

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

vec4 permute(vec4 x) {
  return mod289(((x * 34.0) + 1.0) * x);
}

vec4 taylorInvSqrt(vec4 r) {
  return 1.79284291400159 - 0.85373472095314 * r;
}

float snoise(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);
  vec3 i = floor(v + dot(v, C.yyy));
  vec3 x0 = v - i + dot(i, C.xxx);
  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);
  vec3 x1 = x0 - i1 + C.xxx;
  vec3 x2 = x0 - i2 + C.yyy;
  vec3 x3 = x0 - D.yyy;
  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)
  );
  float n_ = 0.142857142857;
  vec3  ns = n_ * D.wyz - D.xzx;
  vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
  vec4 x_ = floor(j * ns.z);
  vec4 y_ = floor(j - 7.0 * x_);
  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 = 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);
  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;
  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)))
  );
}

float clamps(float x) { return clamp(x, 0.0, 1.0); }
vec3 clamps(vec3 x) { return clamp(x, 0.0, 1.0); }

vec4 cells(vec2 i, vec2 uv, float t, float noiseSpeed, float noiseScale) {
  float n = snoise(vec3(vec2(i / noiseScale), ((3.0 * fft) + t) / (1.0 / noiseSpeed)));
  n = clamp(n, 0.05, 0.97);
  vec3 luminosity = vec3(n);
  vec3 color = vec3(
    clamps(cos(sin(n + t * 0.3) / 4.0 + 0.55)),
    clamps(cos(sin(n + t * 1.1) / 3.0 + 0.55)),
    clamps(sin(cos(n + t * 1.2) / 4.0 + 0.55))
  );
  if (color.r > 0.9) { color.b += 0.4; }
  if (color.g > 0.8) { color.g -= 0.1; color.r += 0.3; }
  if (color.b > 0.7) { color.r -= 0.1; color.g += 0.2; }
  return vec4(luminosity * sqrt(color.zyx * 1.2), n);
}

void main(void) {
  const float cellCount = 96.0;
  float frameScale = 24.0;
  float frameTime = floor(time * frameScale) / frameScale;
  float noiseSpeed = 0.3;
  float noiseScale = 13.0;
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  uv.y += frameTime * 0.015;
  float minRes = min(resolution.x, resolution.y);
  vec2 fc = gl_FragCoord.xy / minRes;
  float wt = frameTime * bgWaveSpeed;
  float xAngle = wt + fc.y * ySineCycles;
  float yAngle = wt + fc.x * xSineCycles;
  bool bxHalf, byHalf;
  vec2 distortOffset = vec2(sin(xAngle), sin(yAngle)) * vec2(xDistMag, yDistMag) * 0.25;
  uv += distortOffset;
  uv.y /= (resolution.x / resolution.y);
  uv *= cellCount;
  vec2 i = floor(uv);
  vec2 f = fract(uv);
  f = f - 0.5;
  i = i + 0.5;
  vec4 cellNoise = cells(i, uv / cellCount, frameTime, noiseSpeed, noiseScale);
  vec3 cell = cellNoise.xyz;
  float n = cellNoise.w;
  vec3 baseColor = clamp(2.0 - cell, 0.0, 1.0);
  float cellRadius = (n > 0.1) ? 0.75 - (fft * 0.5) : 1.0;
  vec3 color = mix(
    baseColor * cell * 2.0,
    cell,
    smoothstep(0.0, 0.05, cellRadius - length(f))
  );
  color *= clamps(mix(color, color * color + vec3(n * 0.1, n * 0.3, n * 0.5), 0.5));
  color = hue(color, frameTime - n);
  gl_FragColor = vec4(color, 1.0);
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm1Texture;
uniform vec2 resolution;
uniform float time;

float hash(vec2 p) {
  return fract(sin(dot(p, vec2(41.0, 289.0))) * 45758.5453);
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec4 col = texture2D(prgm1Texture, uv);
  float w = 0.1;
  vec2 a = vec2(uv.x - 0.5, uv.y - 0.66);
  vec2 b = a * 0.15 / float(10.0);
  uv += b * (hash(uv.xy + fract(time)) * 2.0);
  for (float i = 1.0; i > 0.8; i-= 0.00125) {
    uv -= 0.5;
    uv *= i;
    uv += 0.5;
    col += texture2D(prgm1Texture, uv) * w * 1.5;
    w *= 0.95;
  }
  col *= 0.9;
  gl_FragColor = col;
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm2Texture;
uniform vec2 resolution;
uniform float time;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float hardscan = -16.0; // -8.0 = soft | -16.0 = medium
const float hardPix = -4.0; // -2.0 = soft | -4.0 = hard
const float maskDark = 0.5;
const float maskLight = 2.5;

float toLinear(float c) {
  return (c <= 0.04045) ? c / 12.92 : pow(abs((c + 0.055) / 1.055), 2.4);
}

vec3 toLinear(vec3 c) {
  return vec3(toLinear(c.r), toLinear(c.g), toLinear(c.b));
}

float toSRGB(float c) {
  return(c < 0.0031308 ? c * 12.92 : 1.055 * pow(abs(c), 0.41666) - 0.055);
}

vec3 toSRGB(vec3 c) {
  return vec3(toSRGB(c.r), toSRGB(c.g), toSRGB(c.b));
}

vec3 fetch(vec2 pos, vec2 off, vec2 res) {
  pos = floor(pos * res + off) / res;
  if (max(abs(pos.x - 0.5), abs(pos.y - 0.5)) > 0.5) {
    return vec3(0.0);
  }
  return toLinear(texture2D(prgm2Texture, pos.xy, -16.0).xyz);
}

vec2 dist(vec2 pos, vec2 res) {
  pos = pos * res;
  return -((pos - floor(pos)) - vec2(0.5));
}

float gauss(float pos, float scale) {
  return exp2(scale * pos * pos);
}

vec3 horz3(vec2 pos, float off, vec2 res) {
  vec3 b = fetch(pos, vec2(-1.0, off), res);
  vec3 c = fetch(pos, vec2(+0.0, off), res);
  vec3 d = fetch(pos, vec2(+1.0, off), res);
  float dst = dist(pos, res).x;
  float scale = hardPix;
  float wb = gauss(dst - 1.0, scale);
  float wc = gauss(dst + 0.0, scale);
  float wd = gauss(dst + 1.0, scale);
  return (b * wb + c * wc + d * wd) / (wb + wc + wd);
}

vec3 horz5(vec2 pos, float off, vec2 res) {
  vec3 a = fetch(pos, vec2(-2.0, off), res);
  vec3 b = fetch(pos, vec2(-1.0, off), res);
  vec3 c = fetch(pos, vec2(+0.0, off), res);
  vec3 d = fetch(pos, vec2(+1.0, off), res);
  vec3 e = fetch(pos, vec2(+2.0, off), res);
  float dst = dist(pos, res).x;
  float scale = hardPix;
  float wa = gauss(dst - 2.0, scale);
  float wb = gauss(dst - 1.0, scale);
  float wc = gauss(dst + 0.0, scale);
  float wd = gauss(dst + 1.0, scale);
  float we = gauss(dst + 2.0, scale);
  return (a * wa + b * wb + c * wc + d * wd + e * we) / (wa + wb + wc + wd + we);
}

float scan(vec2 pos, float off, vec2 res) {
  float dst = dist(pos, res).y;
  return gauss(dst + off, hardscan);
}

vec3 tri(vec2 pos, vec2 res) {
  vec3 a = horz3(pos, -1.0, res);
  vec3 b = horz5(pos, +0.0, res);
  vec3 c = horz3(pos, +1.0, res);
  float wa = scan(pos, -1.0, res);
  float wb = scan(pos, +0.0, res);
  float wc = scan(pos, +1.0, res);
  return a * wa + b * wb + c * wc;
}

vec3 mask(vec2 pos) {
  pos.x += pos.y * 3.0;
  vec3 m = vec3(maskDark, maskDark, maskDark);
  pos.x = fract(pos.x / 6.0);
  if (pos.x < 0.333) {
    m.r = maskLight;
  } else if (pos.x < 0.666) {
    m.g = maskLight;
  } else {
    m.b = maskLight;
  }
  return m;
}

float bar(float pos, float bar) {
  pos -= bar;
  return pos * pos < 4.0 ? 0.0 : 1.0;
}

float rand(vec2 uv, float t) {
  float seed = dot(uv, vec2(12.9898, 78.233));
  return fract(sin(seed) * 43758.5453123 + t);
}

float gaussian(float z, float u, float o) {
  return (
    (1.0 / (o * sqrt(TAU))) *
    (exp(-(((z - u) * (z - u)) / (2.0 * (o * o)))))
  );
}

vec3 gaussgrain(float t) {
  vec2 ps = vec2(1.0) / resolution.xy;
  vec2 uv = gl_FragCoord.xy * ps;
  float noise = rand(uv, t);
  noise = gaussian(noise, 0.0, 0.5);
  return vec3(noise);
}

vec2 warp(vec2 uv, vec2 warpAmount) {
  uv = uv * 2.0 - 1.0;
  vec2 offset = abs(uv.yx) / vec2(warpAmount.x, warpAmount.y);
  uv = uv + uv * offset * offset;
  uv = uv * 0.5 + 0.5;
  return uv;
}

void drawVig(inout vec3 color, vec2 uv) {
  float vignette = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);
  vignette = clamp(pow(abs(16.0 * vignette), 0.1), 0.0, 1.0);
  color *= vignette;
}

void main(void) {
  vec2 warpAmount = vec2(7.0, 5.0);
  vec2 res = vec2(resolution.x / 4.0, resolution.y / 3.0);
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  float vig = (0.0 + 1.0 * 21.0 * uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y));
  float v = exp(-0.01 * length(uv)) * vig;
  float frameScale = 29.97;
  float frameTime = floor(time * frameScale) / frameScale;
  vec3 g = gaussgrain(frameTime) * 0.07;
  vec2 pos = mix(uv, warp(uv, warpAmount), 0.75);
  vec4 color = vec4(tri(pos, res) * mask(gl_FragCoord.xy), 1.0);
  color.xyz = toSRGB(color.xyz * 2.0) - g;
  color = mix(color, color * v, 0.7);
  if (pos.x < 0.0 || pos.x > 1.0 || pos.y < 0.0 || pos.y > 1.0) {
    color = texture2D(prgm2Texture, uv) * 0.1;
  }
  gl_FragColor = color;
}