#version 300 es
// Marco Gomez - @TheCodeTherapy - https://mgz.me
// Inspired by: PS3 XMB https://www.youtube.com/watch?v=ZuUmT4XL-bQ
precision highp float;
in vec2 vUv;
uniform vec2 resolution;
uniform float time;
uniform float fft;
out vec4 fragColor;
const vec3 colA = vec3(0.1, 0.3, 0.6);
const vec3 colB = vec3(0.0, 0.1, 0.5);
const vec3 colWave = vec3(0.35, 0.36, 0.37);
const float widthFactor = 1.5;
const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float PHI = (1.0 + sqrt(5.0)) / 2.0;
const float TAN30 = 1.0 / sqrt(3.0);
const vec2 hashv2 = vec2(12.9898, 78.233);
const float hashS = 43758.5453123;
#define ss(a, b, t) smoothstep(a, b, t)
#define clamps(a) clamp(a, 0.0, 1.0)
vec2 distortUV(vec2 uv, float freqX, float freqY, float distMult, float speed) {
const float xDistMag = 0.02;
const float yDistMag = 0.12;
float minRes = min(resolution.x, resolution.y);
vec2 fc = gl_FragCoord.xy / minRes;
float wt = time * speed;
float xAngle = wt + fc.y * freqY;
float yAngle = wt + fc.x * freqX;
bool bxHalf, byHalf;
vec2 distortOffset = vec2(sin(xAngle), sin(yAngle)) * vec2(xDistMag, yDistMag) * 0.5;
uv += distortOffset * distMult;
return uv;
}
vec3 waveDist(float speed, float freq, float ampl, float offset, float width, bool up) {
vec2 uv = distortUV(vUv, TAU * 0.4, TAU, 0.6, 0.5);
float t = time + 300.0;
float angle = t * speed * freq * -1.0 + uv.x * 2.0;
float y = sin(angle) * ampl + offset;
float diff = y - uv.y;
bool positive = y - uv.y > 0.0 && uv.y != 0.0;
float dist = distance(y, uv.y);
float scale = 1.0;
dist = up && positive || !up && !positive ? dist * 3.0 : dist;
scale = pow(ss(width, 0.0, dist), 5.0);
return min(colWave * scale, colWave);
}
float lineDist(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a;
vec2 ba = b - a;
float t = clamps(dot(pa, ba) / dot(ba, ba));
return length(pa - ba * t);
}
float hash(vec2 uv) {
return fract(sin(dot(uv.xy, vec2(12.9898, 78.233))) * 43758.5453);
}
vec2 hash2(vec2 uv) {
return vec2(hash(uv), hash(uv) * PHI);
}
vec2 getRandomPos(vec2 gID, float posTime) {
vec2 rnd = hash2(gID) * posTime + fft * 2.0;
return sin(rnd) * 0.35;
}
float getDots(vec2 uv, float uvMult, float posTime) {
uv *= uvMult;
vec2 gUV = fract(uv) - 0.5;
vec2 gID = floor(uv);
vec2 rndP = getRandomPos(gID, posTime);
float rndDot = length(gUV - rndP);
return ss(0.17, 0.01, rndDot);
}
float osc(float s, float e, float t) {
return (e - s) * 0.5 + s + sin(t) * (e - s) * 0.5;
}
vec3 hue(vec3 col, float a) {
const vec3 k = vec3(TAN30);
float c = cos(a);
return col * c + cross(k, col) * sin(a) + k * dot(k, col) * (1.0 - c);
}
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 seed = dot(uv, hashv2);
float noise = fract(sin(seed) * hashS + t);
noise = gaussian(noise, 0.0, 0.5);
return vec3(noise);
}
void main(void) {
vec3 color = vec3(mix(colA, colB, vUv.x * vUv.y));
float inten = 0.65 + fft * 0.2;
float amplScale = 0.6;
float speedMult = 0.6;
color += waveDist(0.15 * speedMult, 0.26, 0.07 * amplScale, 0.35, 0.10, true) * inten;
color += waveDist(0.21 * speedMult, 0.20, 0.20 * amplScale, 0.52, 0.10, false) * inten;
color += waveDist(0.22 * speedMult, 0.58, 0.05 * amplScale, 0.30, 0.20, true) * inten;
color += waveDist(0.30 * speedMult, 0.36, 0.07 * amplScale, 0.33, 0.10, true) * inten;
color += waveDist(0.32 * speedMult, 0.60, 0.15 * amplScale, 0.45, 0.05, false) * inten;
color += waveDist(0.44 * speedMult, 0.40, 0.15 * amplScale, 0.51, 0.10, false) * inten;
color += waveDist(0.51 * speedMult, 0.46, 0.07 * amplScale, 0.30, 0.05, true) * inten;
vec2 uv = (gl_FragCoord.xy - 0.5 * resolution.xy) / resolution.y;
float dots = 0.03;
for (float i = 1.0; i < 5.0; i += 1.0) {
dots += dots * getDots(uv + i * 2.0, 27.0 + i * 2.0, (time + 100.0) * (0.5 + i / 12.0)) * (1.8 + fft * 4.0);
}
uv = distortUV(uv, TAU * 0.7, TAU, 1.0, 0.2);
float particlesStripe = 1.0 - length(uv.y * 2.0);
dots *= dots * dots * 50.0 * particlesStripe;
color += pow(clamps(dots * (1.0 - length(uv.y * 3.0))), 1.2);
float fade = clamps(time * 0.25 - 0.125);
color = hue(color, osc(-0.1, -0.03, time));
color = mix(color, color * color, osc(0.3, 0.6, time * 0.3)) - gaussgrain(time * 0.21) * 0.04;
fragColor = vec4(color * fade, 1.0);
}