Back to shaders

Shader test bench

20250324

glsl-daily-practice generative glsl runnable fragment MIT
Source
runnable fragment

Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.

Code

precision mediump float;
// "Immersive Animated Flower of Life" Shader
//
// Uniforms expected:
//   - u_time (float): Time in seconds
//   - u_resolution (vec2): The width and height of the viewport
//
// The final color is written to fragColor.

uniform float u_time;
uniform vec2 u_resolution;
#define fragColor gl_FragColor

// ---------------------------------------------------
// 1) Basic hash and noise functions with fbm
// ---------------------------------------------------
float hash21(vec2 p) {
    p = fract(p * vec2(234.34, 435.345));
    p += dot(p, p + 34.345);
    return fract(p.x * p.y);
}

float noise2D(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    float a = hash21(i);
    float b = hash21(i + vec2(1.0, 0.0));
    float c = hash21(i + vec2(0.0, 1.0));
    float d = hash21(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

float fbm(vec2 p) {
    float value = 0.0;
    float amplitude = 0.5;
    float frequency = 1.0;
    for (int i = 0; i < 4; i++) {
        value += amplitude * noise2D(p * frequency);
        frequency *= 2.0;
        amplitude *= 0.5;
    }
    return value;
}

// ---------------------------------------------------
// 2) Hue rotation utility (HSV-like)
// ---------------------------------------------------
vec3 hueColor(float h) {
    h = fract(h);
    float r = abs(h * 6.0 - 3.0) - 1.0;
    float g = 2.0 - abs(h * 6.0 - 2.0);
    float b = 2.0 - abs(h * 6.0 - 4.0);
    return clamp(vec3(r, g, b), 0.0, 1.0);
}

// ---------------------------------------------------
// 3) Circle ring function with soft glow
// ---------------------------------------------------
float circleRing(vec2 pos, vec2 center, float radius, float thickness) {
    float dist = abs(length(pos - center) - radius);
    return smoothstep(thickness, 0.0, dist);
}

// ---------------------------------------------------
// 4) Immersive Flower of Life pattern with animated rotation & vortex warp
// ---------------------------------------------------
float flowerOfLife(vec2 uv) {
    float R = 0.35;
    // Pulsating ring thickness for a breathing effect
    float ringThickness = 0.015 + 0.005 * sin(u_time * 2.0);
    float coverage = 0.0;
    
    // Introduce a subtle vortex distortion to simulate depth
    float vortex = 0.1 * sin(u_time + length(uv) * 10.0);
    float angleOffset = vortex;
    
    // Global rotation offset for the entire pattern
    float rotationOffset = u_time * 0.15;
    
    // Central circle
    coverage += circleRing(uv, vec2(0.0), R, ringThickness);
    
    // First ring (6 circles)
    for (int i = 0; i < 6; i++) {
        float angle = 2.0 * 3.14159 * float(i) / 6.0 + rotationOffset + angleOffset;
        vec2 c = vec2(cos(angle), sin(angle)) * R;
        coverage += circleRing(uv, c, R, ringThickness);
    }
    
    // Second ring (12 circles)
    for (int i = 0; i < 12; i++) {
        float angle = 2.0 * 3.14159 * float(i) / 12.0 + rotationOffset + angleOffset;
        vec2 c = vec2(cos(angle), sin(angle)) * (2.0 * R);
        coverage += circleRing(uv, c, R, ringThickness);
    }
    
    // Optional Third ring (18 circles) for added depth
    for (int i = 0; i < 18; i++) {
        float angle = 2.0 * 3.14159 * float(i) / 18.0 + rotationOffset + angleOffset;
        vec2 c = vec2(cos(angle), sin(angle)) * (3.0 * R);
        coverage += circleRing(uv, c, R, ringThickness);
    }
    
    return coverage;
}

// ---------------------------------------------------
// 5) Animated particle field for immersive foreground sparkle
// ---------------------------------------------------
float particles(vec2 uv, float scale) {
    // Create a moving grid of particles
    vec2 grid = fract(uv * scale);
    vec2 id = floor(uv * scale);
    float n = noise2D(id + u_time * 0.1);
    // Particles appear when within a small central region of each cell
    float particle = smoothstep(0.3, 0.2, length(grid - 0.5));
    return particle * n;
}

// ---------------------------------------------------
// 6) Main shader function: Layering immersive animation
// ---------------------------------------------------
void main() {
    // Normalize coordinates with a subtle time-based zoom to enhance immersion
    vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / u_resolution.y;
    uv *= 1.0 + 0.05 * sin(u_time * 0.5);
    
    float len = length(uv);
    float angle = atan(uv.y, uv.x);
    
    // Layer 1: Immersive Background
    // Apply a slow rotation and warp to create a fluid, organic backdrop
    vec2 bgUV = uv;
    float bgRotation = 0.1 * u_time;
    float ca = cos(bgRotation);
    float sa = sin(bgRotation);
    bgUV = vec2(bgUV.x * ca - bgUV.y * sa, bgUV.x * sa + bgUV.y * ca);
    float bgNoise = fbm(bgUV * 2.0 + u_time * 0.2);
    vec3 bgColor = mix(vec3(0.05, 0.02, 0.1), vec3(0.1, 0.15, 0.3), bgNoise);
    bgColor *= smoothstep(1.2, 0.0, len);
    
    // Layer 2: Immersive Flower of Life Pattern
    // Add an additional swirling effect to the pattern for a sense of depth
    vec2 patternUV = uv;
    float swirlAmount = 0.5 * sin(len * 4.0 - u_time * 0.3);
    float pca = cos(swirlAmount);
    float psa = sin(swirlAmount);
    patternUV = vec2(patternUV.x * pca - patternUV.y * psa, patternUV.x * psa + patternUV.y * pca);
    float pattern = flowerOfLife(patternUV);
    
    // Base hue modulated over time and space for a vibrant look
    float baseHue = 0.55 + 0.1 * sin(u_time * 0.4);
    float hueMod = baseHue + 0.1 * sin(angle * 5.0) + 0.15 * sin(len * 3.0 - u_time * 0.6);
    vec3 patternColor = hueColor(hueMod);
    vec3 patternLayer = patternColor * pattern * (1.0 - smoothstep(0.0, 1.2, len));
    
    // Layer 3: Animated Particle Foreground
    float part = particles(uv, 20.0);
    vec3 particleColor = vec3(1.0, 0.9, 0.8) * part;
    
    // Combine layers using additive blending
    vec3 color = bgColor + patternLayer + particleColor;
    
    // Add a deep cosmic glow that intensifies near the center
    float glow = 0.25 / (len + 0.1);
    color += glow * vec3(1.2, 1.1, 0.9);
    
    // Final gamma correction and brightness boost for a truly immersive feel
    color = pow(color, vec3(1.4));
    color *= 1.8;
    
    fragColor = vec4(color, 1.0);
}