All entries

No still was sent with this entry.

Source

"use typeshade";

// -------------------------------------------------------------------
// Original Code: https://www.shadertoy.com/view/Wt33Wf
//
// Created by kaiware007 in 2020-01-28
//
// Shader License: CC BY 3.0
// Author: Jan Mróz (jaszunio15)
// -------------------------------------------------------------------

class Uniforms {
  time: f32;
  resolution: vec2;
  mouse: vec2;
}

declare const u: uniform<Uniforms>;

// -------------------------------------------------------------------
// SDF primitives
// -------------------------------------------------------------------

class SDFLine {
  a: vec2;
  b: vec2;

  constructor(a: vec2, b: vec2) {
    this.a = a;
    this.b = b;
  }

  distance(p: vec2): f32 {
    const pa = p - this.a;
    const ba = this.b - this.a;
    const h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);

    return length(pa - ba * h);
  }
}

class SDFBox {
  halfSize: vec2;

  constructor(halfSize: vec2) {
    this.halfSize = halfSize;
  }

  distance(p: vec2): f32 {
    const d = abs(p) - this.halfSize;

    return length(max(d, vec2(0.0))) + min(max(d.x, d.y), 0.0);
  }
}

class SDFTrapezoid {
  r1: f32;
  r2: f32;
  height: f32;

  constructor(r1: f32, r2: f32, height: f32) {
    this.r1 = r1;
    this.r2 = r2;
    this.height = height;
  }

  private dot2(v: vec2): f32 {
    return dot(v, v);
  }

  distance(p: vec2): f32 {
    const k1 = vec2(this.r2, this.height);
    const k2 = vec2(this.r2 - this.r1, 2.0 * this.height);
    const px = abs(p.x);
    const q = vec2(px, p.y);

    const ca = vec2(
      px - min(px, q.y < 0.0 ? this.r1 : this.r2),
      abs(q.y) - this.height
    );

    const cb =
      q -
      k1 +
      k2 * clamp(dot(k1 - q, k2) / this.dot2(k2), 0.0, 1.0);

    const s = cb.x < 0.0 && ca.y < 0.0 ? -1.0 : 1.0;

    return s * sqrt(min(this.dot2(ca), this.dot2(cb)));
  }
}

// -------------------------------------------------------------------
// Scene elements
// -------------------------------------------------------------------

class Sun {
  time: f32;
  battery: f32;

  constructor(time: f32, battery: f32) {
    this.time = time;
    this.battery = battery;
  }

  value(uv: vec2): f32 {
    const radius = length(uv);
    const val = smoothstep(0.3, 0.29, radius);
    const bloom = smoothstep(0.7, 0.0, radius);

    let cut =
      3.0 * sin((uv.y + this.time * 0.2 * (this.battery + 0.02)) * 100.0) +
      clamp(uv.y * 14.0 + 1.0, -6.0, 6.0);

    cut = clamp(cut, 0.0, 1.0);

    return clamp(val * cut, 0.0, 1.0) + bloom * 0.6;
  }
}

class Grid {
  time: f32;

  constructor(time: f32) {
    this.time = time;
  }

  value(uv: vec2, battery: f32): f32 {
    const size = vec2(uv.y, uv.y * uv.y * 0.2) * 0.01;
    const shiftedUV = uv + vec2(0.0, this.time * 4.0 * (battery + 0.05));
    const fractUV = abs(fract(shiftedUV) - 0.5);

    let lines = smoothstep(size, vec2(0.0), fractUV);
    lines += smoothstep(size * 5.0, vec2(0.0), fractUV) * 0.4 * battery;

    return clamp(lines.x + lines.y, 0.0, 3.0);
  }
}

class Fuji {
  battery: f32;

  constructor(battery: f32) {
    this.battery = battery;
  }

  distance(p: vec2): f32 {
    const shape = new SDFTrapezoid(
      1.75 + pow(p.y * p.y, 2.1),
      0.2,
      0.5
    );

    return shape.distance(p + vec2(-0.75, 0.5));
  }

  colorFactor(p: vec2): f32 {
    return min(p.y * 4.5 - 0.5, 1.0);
  }
}

class Cloud {
  a1: vec2;
  b1: vec2;
  a2: vec2;
  b2: vec2;
  width: f32;

  constructor(
    a1: vec2,
    b1: vec2,
    a2: vec2,
    b2: vec2,
    width: f32
  ) {
    this.a1 = a1;
    this.b1 = b1;
    this.a2 = a2;
    this.b2 = b2;
    this.width = width;
  }

  private smoothUnion(d1: f32, d2: f32, k: f32): f32 {
    const h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
    return mix(d2, d1, h) - k * h * (1.0 - h);
  }

  distance(p: vec2): f32 {
    const line1 = new SDFLine(this.a1, this.b1);
    const line2 = new SDFLine(this.a2, this.b2);
    const lineVal1 = line1.distance(p);
    const lineVal2 = line2.distance(p);

    const ww = vec2(this.width * 1.5, 0.0);
    const left = max(this.a1 + ww, this.a2 + ww);
    const right = min(this.b1 - ww, this.b2 - ww);
    const boxCenter = (left + right) * 0.5;
    const boxH = abs(this.a2.y - this.a1.y) * 0.5;

    const box = new SDFBox(vec2(0.04, boxH));
    const boxVal = box.distance(p - boxCenter) + this.width;

    const union1 = this.smoothUnion(lineVal1, boxVal, 0.05);
    const union2 = this.smoothUnion(lineVal2, boxVal, 0.05);

    return min(union1, union2);
  }
}

// -------------------------------------------------------------------
// Scene
// -------------------------------------------------------------------

class RetroScene {
  time: f32;
  resolution: vec2;
  battery: f32;

  constructor(time: f32, resolution: vec2, battery: f32) {
    this.time = time;
    this.resolution = resolution;
    this.battery = battery;
  }

  private aspect(): f32 {
    return this.resolution.x / this.resolution.y;
  }

  private project(uv: vec2): vec2 {
    return (uv * 2.0 - 1.0) * vec2(this.aspect(), 1.0);
  }

  private renderGrid(p: vec2, baseColor: vec3): vec3 {
    let col = baseColor;
    let gridUV = p;

    gridUV.y = 3.0 / (abs(gridUV.y + 0.2) + 0.05);
    gridUV.x *= gridUV.y;

    const grid = new Grid(this.time);
    const gridValue = grid.value(gridUV, this.battery);

    col = mix(col, vec3(1.0, 0.5, 1.0), gridValue);

    return col;
  }

  private renderSky(p: vec2, baseColor: vec3): vec3 {
    let col = baseColor;
    let q = p;

    const fujiD = min(q.y * 4.5 - 0.5, 1.0);
    q.y -= this.battery * 1.1 - 0.51;

    // Sun
    let sunUV = q;
    sunUV += vec2(0.75, 0.2);

    col = vec3(1.0, 0.2, 1.0);

    const sun = new Sun(this.time, this.battery);
    const sunValue = sun.value(sunUV);

    col = mix(col, vec3(1.0, 0.4, 0.1), sunUV.y * 2.0 + 0.2);
    col = mix(vec3(0.0), col, sunValue);

    // Fuji
    const fuji = new Fuji(this.battery);
    const fujiValue = fuji.distance(q);

    const waveValue =
      q.y + sin(q.x * 20.0 + this.time * 2.0) * 0.05 + 0.2;
    const waveWidth = smoothstep(0.0, 0.01, waveValue);

    const fujiBase = mix(
      vec3(0.0, 0.0, 0.25),
      vec3(1.0, 0.0, 0.5),
      fujiD
    );

    col = mix(col, fujiBase, step(fujiValue, 0.0));
    col = mix(
      col,
      vec3(1.0, 0.5, 1.0),
      waveWidth * step(fujiValue, 0.0)
    );

    col = mix(
      col,
      vec3(1.0, 0.5, 1.0),
      1.0 - smoothstep(0.0, 0.01, abs(fujiValue))
    );

    // Horizon
    col += mix(
      col,
      mix(
        vec3(1.0, 0.12, 0.8),
        vec3(0.0, 0.0, 0.2),
        clamp(q.y * 3.5 + 3.0, 0.0, 1.0)
      ),
      step(0.0, fujiValue)
    );

    // Clouds
    let cloudUV = q;
    cloudUV.x = mod(cloudUV.x + this.time * 0.1, 4.0) - 2.0;

    const cloudTime = this.time * 0.5;

    let cloudY: f32 = -0.5;

    const cloud1 = new Cloud(
      vec2(0.1 + sin(cloudTime + 140.5) * 0.1, cloudY),
      vec2(1.05 + cos(cloudTime * 0.9 - 36.56) * 0.1, cloudY),
      vec2(
        0.2 + cos(cloudTime * 0.867 + 387.165) * 0.1,
        0.25 + cloudY
      ),
      vec2(
        0.5 + cos(cloudTime * 0.9675 - 15.162) * 0.09,
        0.25 + cloudY
      ),
      0.075
    );

    const cloudValue1 = cloud1.distance(cloudUV);

    cloudY = -0.6;

    const cloud2 = new Cloud(
      vec2(
        -0.9 + cos(cloudTime * 1.02 + 541.75) * 0.1,
        cloudY
      ),
      vec2(
        -0.5 + sin(cloudTime * 0.9 - 316.56) * 0.1,
        cloudY
      ),
      vec2(
        -1.5 + cos(cloudTime * 0.867 + 37.165) * 0.1,
        0.25 + cloudY
      ),
      vec2(
        -0.6 + sin(cloudTime * 0.9675 + 665.162) * 0.09,
        0.25 + cloudY
      ),
      0.075
    );

    const cloudValue2 = cloud2.distance(cloudUV);
    const cloudValue = min(cloudValue1, cloudValue2);

    col = mix(
      col,
      vec3(0.0, 0.0, 0.2),
      1.0 - smoothstep(0.075 - 0.0001, 0.075, cloudValue)
    );

    col +=
      vec3(1.0) *
      (1.0 - smoothstep(0.0, 0.01, abs(cloudValue - 0.075)));

    return col;
  }

  colorAt(uv: vec2): vec4 {
    const p = this.project(uv);
    const fog = smoothstep(0.1, -0.02, abs(p.y + 0.2));

    let col = vec3(0.0, 0.1, 0.2);

    if (p.y < -0.2) {
      col = this.renderGrid(p, col);
    } else {
      col = this.renderSky(p, col);
    }

    col += fog * fog * fog;
    col = mix(vec3(col.r) * 0.5, col, this.battery * 0.7);

    return vec4(col, 1.0);
  }
}

// -------------------------------------------------------------------
// Fragment shader
// -------------------------------------------------------------------

@fragment
export function main(@location(0) uv: vec2): vec4 {
  const scene = new RetroScene(u.time, u.resolution, 1.0);
  return scene.colorAt(uv);
}