#version 410 core #ifdef GL_ES precision mediump float; #endif out vec4 FragColor; // Output to screen uniform vec2 u_resolution; // <-- screen resolution from CPU uniform float u_time; // <-- time from CPU uniform float u_scale; // <-- scale from CPU uniform vec2 u_mouse; // <-- mouse from CPU vec3 hsv2rgb(vec3 c) { vec3 rgb = clamp( abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0 ); return c.z * mix(vec3(1.0), rgb, c.y); } vec3 getPaletteColor(float idx, float seed) { float baseHue = fract(seed); // 0..1 base hue float sat = 0.9; float val = 0.9; float hue = fract(baseHue + (idx * 0.33)); return hsv2rgb(vec3(hue, sat, val)); } vec2 random(vec2 p) { return normalize(vec2( fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453), fract(sin(dot(p, vec2(269.5, 183.3))) * 43758.5453) ) * 2.0 - 1.0); } float perlinNoise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); vec2 g00 = random(i + vec2(0.0,0.0)); vec2 g10 = random(i + vec2(1.0,0.0)); vec2 g01 = random(i + vec2(0.0,1.0)); vec2 g11 = random(i + vec2(1.0,1.0)); float n00 = dot(g00, f - vec2(0.0,0.0)); float n10 = dot(g10, f - vec2(1.0,0.0)); float n01 = dot(g01, f - vec2(0.0,1.0)); float n11 = dot(g11, f - vec2(1.0,1.0)); vec2 u = f*f*(3.0-2.0*f); return mix(mix(n00, n10, u.x), mix(n01, n11, u.x), u.y); } mat2 rotate2d(float angle){ return mat2(cos(angle),-sin(angle), sin(angle),cos(angle)); } vec2 morphingSeed(float t, float interval) { float phase = floor(t / interval); float blend = fract(t / interval); vec2 seedA = vec2( sin(phase * 12.9898), cos(phase * 78.233) ); vec2 seedB = vec2( sin((phase+1.0) * 12.9898), cos((phase+1.0) * 78.233) ); blend = smoothstep(0.0, 1.0, blend); return mix(seedA, seedB, blend); } void main() { vec2 st = gl_FragCoord.xy / u_resolution.xy; // Normalize coordinates st.x *= u_resolution.x / u_resolution.y; // Correct aspect ratio st -= 0.5; // Center coordinates st += vec2(100.0,40.0); st *= 2.05 * u_scale; // Zoom out vec2 seed = morphingSeed(u_time, 10.0); // 10 second interval vec2 pos = st; // 15 second interval pos += vec2(0.3, 0.1) * u_time * 0.1; float pre_noise = perlinNoise((pos) * 1.5); // N = [0..1] // noise += 0.6 * perlinNoise(pos * 4.0); pos += rotate2d(pre_noise) * pos * 0.2; pos += u_time * 0.5; float noise = perlinNoise(pos + seed * 2.0); // noise = smoothstep(0.0, 1.0, noise); // Smooth the noise // Normalize noise to [0..1] noise = noise + 0.5; vec3 color; if (noise >= 0.85) { color = getPaletteColor(u_time * 0.1, noise); } else if (noise >= 0.75 ) { color = getPaletteColor((u_time * 0.1) + 1.0, noise); // Estimate gradient (2D normal) vec2 eps = vec2(0.002, 0.0); float n0 = perlinNoise(pos + seed * 2.0); float nx = perlinNoise(pos + seed * 2.0 + eps.xy) - n0; float ny = perlinNoise(pos + seed * 2.0 + eps.yx) - n0; vec2 normal = normalize(vec2(nx, ny)); // View direction (from pixel to "camera") vec2 viewDir = normalize(-st); // Light direction (moves over time) vec2 lightDir = normalize(vec2(cos(u_time * 0.2), sin(u_time * 0.3))); // Fresnel term (stronger highlight at grazing angles) float fresnel = pow(1.0 - max(dot(viewDir, normal), 0.0), 3.0); // Specular component float spec = pow(max(dot(normal, lightDir), 0.0), 32.0); // Combine Fresnel + spec float gloss = fresnel + 0.6 * spec; // Stronger at edges (transition zone of blob) float edge = smoothstep(0.8, 0.9, noise) * (1.0 - smoothstep(0.9, 1.0, noise)); gloss *= edge * 2.0; // Add colored glossy highlight (slightly bluish tint) color += gloss * vec3(0.8, 0.9, 1.0); } else { color = vec3(0.0); } // Denoise edges -> "Insane look-alike effect" color += mix(color, vec3(0.0), smoothstep(0.0, 0.02, abs(noise - 0.9))); FragColor = vec4(color, 1.0); }