The Code Therapy

VoroDistance to the Horizon

A sky-like sci-fi piece that ended up reminding me of Tron.

Created by marcogomez on Tue, 08 Jun 2021 19:28:09 GMT.


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

uniform sampler2D prgm2Texture;
uniform vec2 resolution;

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec4 prgm2 = texture2D(prgm2Texture, uv);
  gl_FragColor = vec4(prgm2.xyz, 1.0);
}

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

uniform sampler2D noiseTexture;
uniform vec2 resolution;
uniform vec2 mouse;
uniform float time;
uniform float fft;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float rndc = 43758.5453123;

float rand11(float p) {
  return fract(sin(p * 591.32) * rndc);
}

vec2 rand22(vec2 p) {
  return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
}

float osc(float s, float e, float ts) {
  return (e - s) / 2.0 + s + sin(time * ts) * (e - s) / 2.0;
}

float tNoise(vec2 n) {
  n  = fract(n * vec2(5.3987, 5.4421));
  n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
  float xy = n.x * n.y;
  return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
}

float noise(vec2 x) {
  vec2 p = floor(x);
  vec2 f = fract(x);
  f = f * f * (3.0 - 2.0 * f);
  float a = texture2D(noiseTexture, (p + vec2(0.5, 0.5)) / 256.0, 0.0).x;
  float b = texture2D(noiseTexture, (p + vec2(1.5, 0.5)) / 256.0, 0.0).x;
  float c = texture2D(noiseTexture, (p + vec2(0.5, 1.5)) / 256.0, 0.0).x;
  float d = texture2D(noiseTexture, (p + vec2(1.5, 1.5)) / 256.0, 0.0).x;
  return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}

vec4 vignette(vec2 xy, vec4 fragcol, float intensity, bool reverse) {
  xy *= 1.0 - xy.yx;
  float vig = pow(xy.x * xy.y * 8.0, 0.25 + intensity);
  return reverse ? fragcol /= vec4(vig) : fragcol *= vec4(vig);
}

vec3 intersect(vec3 o, vec3 d, vec3 c, vec3 u, vec3 v) {
  vec3 q = o - c;
  return vec3(
    dot(cross(u, v), q),
    dot(cross(q, u), d),
    dot(cross(v, q), d)
  ) / dot(cross(v, u), d);
}

float sky(vec3 p) {
  float a = atan(p.y, p.z);
  float t = time;
  float n = noise(vec2(p.x, p.z));
  float v = (
    rand11(floor(a * 4.0 + t)) * 0.5 +
    rand11(floor(a * 8.0 - t)) * 0.25 +
    rand11(floor(a * 16.0 + t)) * 0.75
  );
  v = smoothstep(0.0, 3.0, v) + n / 4.0;
  return v * 1.0 + fft * 0.5;
}

float ssin(float t) {
  return (2.0 / PI) * atan(sin(TAU * t * 0.5) / 0.1) * 2.0;
}

vec3 voronoi(vec2 x) {
  vec2 n = floor(x), f = fract(x), mg, mr;
  float md = 16.0, md2 = 8.0;
  for(int j = -1; j <= 1; j ++) {
    for(int i = -1; i <= 1; i ++) {
      vec2 g = vec2(float(i), float(j));
      vec2 o = rand22(n + g);
      vec2 r = g + o - f;
      float d = mix(
        abs(r.x) + abs(r.y), // manhattan distance
        max(abs(r.x), abs(r.y)), // chebyshev distance
        clamp(ssin(time * 0.05), 0.0, 1.0)
      );
      if (d < md) {
        md2 = md; md = d; mr = r; mg = g;
      } else if (d < md2) {
        md2 = d;
      }
    }
  }
  return vec3(n + mg, md2 - md);
}

vec2 rotate(vec2 p, float a) {
  return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec2 uvs = uv;
  float ar = resolution.x / resolution.y;
  uv = uv * 2.0 - 1.0;
  uv.x *= ar;
  vec3 ro = vec3(1.0, 0.3, 1.0);
  vec3 ta = vec3(0.0, 0.0, 1.0);
  vec3 ww = normalize(ta - ro);
  vec3 uu = normalize(cross(ww, normalize(vec3(0.0, 1.0, osc(-0.125, 0.125, 0.25)))));
  vec3 vv = normalize(cross(uu, ww));
  vec3 rd = normalize(uv.x * uu + uv.y * vv + ww);
  ro.x -= time * 21.0;
  float inten = 0.0;
  float sd = dot(rd, vec3(-0.01, 0.99, 0.0));
  inten = (
    pow(abs(0.99 - abs(sd)), 32.0 - fft * 64.0) +
    pow(abs(sky(rd)), 6.0) * step(0.0, rd.y) * 2.0
  );
  inten = inten + 0.13 - length(uv) * 0.25;
  vec3 its;
  float v, g;
  for (int i = 0; i < 3; i ++) {
    float fi = float(i) + 1.0;
    float layer = float(i);
    float timea = time * 1.2 * float(i);
    float timeb = time * 0.9 * float(i);
    its = intersect(
      ro, rd,
      vec3(timeb, -30.0 - layer * 30.0, timea),
      vec3(1.0, 0.0, 0.0),
      vec3(0.0, 0.0, 1.0)
    );
    if (its.x > 0.0) {
      vec3 vo = voronoi((its.yz * (i == 0 ? fi : fi * 0.6)) * 0.05 + 8.0 * noise(vec2(float(i))));
      v = exp(-40.0 * (vo.z - 0.05));
      float fx = 0.05;
      if (i == 0) {
        float fxi = cos(vo.x * 18.65 + time * 2.5);
        fx = clamp(smoothstep(0.1, 1.0, fxi), 0.01, 1.9) * (2.0 + fft * 3.0) * noise(vo.zy * 16.0);
        fx *= exp(-1.0 * vo.z) * 1.5;
      } else if (i == 2) {
        float fxi = cos(vo.x * 18.5 + (time * 2.0) * 2.5);
        fx = clamp(smoothstep(0.1, 1.0, fxi), 0.01, 1.9) * (2.0 + fft * 3.0) * noise(vo.zy * 16.0);
        fx *= exp(-4.0 * vo.z) * 1.5;
      }
      fx = smoothstep(0.0, 5.0, fx);
      inten += sqrt(v) * 0.06 + fx;
    }
  }
  vec3 col = pow(vec3(inten * 1.2), vec3(1.0, 1.0, 0.4));
  col *= col;
  gl_FragColor = vignette(uvs, vec4(col, 1.0), fft, true);
}

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

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

const float amount = 1.0;
const float saturation = 0.6;
const vec2 vignetteSize = vec2(0.25, 0.25);
const float vignetteRoundness = 0.12;
const float vignetteMix = 1.0;
const float vignetteSmoothness = 0.42;
const float W = 1.2;
const float T = 7.5;

float filmicReinhardCurve(float x) {
  float q = (T * T + 1.0) * x * x;
  return q / (q + x + T * T);
}

vec3 filmicReinhard(vec3 c) {
  float w = filmicReinhardCurve(W);
  return vec3(
    filmicReinhardCurve(c.r),
    filmicReinhardCurve(c.g),
    filmicReinhardCurve(c.b)
  ) / w;
}

vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con) {
  const float AvgLumR = 0.5;
  const float AvgLumG = 0.5;
  const float AvgLumB = 0.5;
  const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
  vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
  vec3 brtColor = color * brt;
  vec3 intensity = vec3(dot(brtColor, LumCoeff));
  vec3 satColor = mix(intensity, brtColor, sat);
  vec3 conColor = mix(AvgLumin, satColor, con);
  return conColor;
}

float sdSquare(vec2 point, float width) {
  vec2 d = abs(point) - width;
  return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

float vignette(vec2 uv, vec2 size, float roundness, float smoothness) {
  uv -= 0.5;
  float minWidth = min(size.x, size.y);
  uv.x = sign(uv.x) * clamp(abs(uv.x) - abs(minWidth - size.x), 0.0, 1.0);
  uv.y = sign(uv.y) * clamp(abs(uv.y) - abs(minWidth - size.y), 0.0, 1.0);
  float boxSize = minWidth * (1.0 - roundness);
  float dist = sdSquare(uv, boxSize) - (minWidth * roundness);
  return 1.0 - smoothstep(0.0, smoothness, dist);
}

void main(void) {
  float reinhardAmount = 0.4 + fft * 0.6;
  float contrast = 1.0 + fft * 0.25;
  float brightness = 1.5 + fft * 0.5;

  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec4 prgm1 = texture2D(prgm1Texture, uv);
  vec3 reinhard = filmicReinhard(prgm1.rgb);
  vec3 color = prgm1.rgb;
  color = mix(prgm1.rgb, reinhard, reinhardAmount);
  color = ContrastSaturationBrightness(color, brightness, saturation, contrast);
  float v = vignette(uv, vignetteSize, vignetteRoundness, vignetteSmoothness);
  vec3 vig = color * v;
  color = mix(color, vig, vignetteMix);
  color = mix(prgm1.xyz, color, amount);
  color = clamp(color, 0.0, 1.0);
  gl_FragColor = vec4(color, 1.0);
}