No still was sent with this entry.
Cyber Fuji 2020
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);
}