Project_2026-02-12_17-10-02

GLSL shader by scry · created 2026-02-13 · 10s loop · 2 passes

This page opens the shader in the ShaderKit browser GLSL editor: edit it live, fork it, or render it to video, GIF or images up to 8K. Also available as a full-screen view and an embeddable player.

Shader source (GLSL)

Common

#define pi acos(-1.)
#define deg pi/180.  //1 degree
#define time iTime*2.*pi/30. //sin(time) loops 10 seconds
#define R iResolution.xy //shorthand
#define ar R.x/R.y //aspect ratio
#define M iMouse //shorthand
#define xm (M.xy/R) //normalized mouse
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5) //aspect ratio correction
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
    return mat2(cos(a),sin(a),-sin(a),cos(a));
}

Buffer A (iChannel0)

// Scene SDF

float hash31(vec3 p) {
    p = fract(p * vec3(0.1031, 0.1030, 0.0973));
    p += dot(p, p.yzx + 33.33);
    return fract((p.x + p.y) * p.z);
}

// Fractal fold operations
vec3 boxFold(vec3 p, float foldLimit) {
    return clamp(p, -foldLimit, foldLimit) * 2.0 - p;
}

void sphereFold(inout vec3 p, inout float dr, float minR2, float fixedR2) {
    float r2 = dot(p, p);
    if (r2 < minR2) {
        float t = fixedR2 / minR2;
        p *= t; dr *= t;
    } else if (r2 < fixedR2) {
        float t = fixedR2 / r2;
        p *= t; dr *= t;
    }
}

// Mandelbox-inspired fractal SDF
float fractalDE(vec3 p) {
    float scale = -2.0 + 0.3 * sin(time * 0.4);
    float minR2 = 0.25;
    float fixedR2 = 1.0;
    float foldLimit = 1.0 + 0.15 * sin(time * 0.6);
    
    vec3 offset = p;
    float dr = 1.0;
    
    for (int i = 0; i < 8; i++) {
        p = boxFold(p, foldLimit);
        sphereFold(p, dr, minR2, fixedR2);
        
        p = p * scale + offset;
        dr = dr * abs(scale) + 1.0;
        
        // Animated rotation per iteration
        p.xz *= r2d(0.15 * sin(time * 0.3 + float(i) * 0.7));
        p.yz *= r2d(0.1 * cos(time * 0.25 + float(i) * 0.5));
    }
    
    return length(p) / abs(dr);
}

vec4 map(vec3 p) {
    float scene = 1e10;
    //p.z -= 4.0 + 1.0 * sin(time * 0.4);
    
    vec3 o = p;
    p.x += time*0.05;
    float camDist = 4.0 + 1.0 * sin(time * 0.4);
    float camAngle = time * 0.25;
    vec3 ro = vec3(camDist * cos(camAngle), 1.0 * sin(time * 0.3), camDist * sin(camAngle));
    o -= ro; 
    // Global rotation
    p.xz *= r2d(time * 0.2);
    p.yz *= r2d(time * 0.15);
    
    float s = 0.2;
    p = (fract(p*s)-0.5)/s;
    // Main fractal
    scene = fractalDE(p)-0.001;
    
    // Add subtle displacement for organic feel
    float disp = sin(p.x * 8.0 + time * 1.5) * sin(p.y * 8.0 + time * 1.2) * sin(p.z * 8.0 + time * 0.9) * 0.01;
    //scene -= 0.003;
    //scene += disp;
    scene = max(scene,-length(o)+2.2+scene*0.5);
    return vec4(p, scene);
}

vec3 calcNormal(vec3 p) {
    vec2 e = vec2(0.0005, 0.0);
    return normalize(vec3(
        map(p + e.xyy).w - map(p - e.xyy).w,
        map(p + e.yxy).w - map(p - e.yxy).w,
        map(p + e.yyx).w - map(p - e.yyx).w
    ));
}

vec2 RM(vec3 ro, vec3 rd) {
    float dO = 0.0;
    float ii = 0.0;
    for (int i = 0; i < 100; i++) {
        vec3 p = ro + rd * dO;
        float dS = map(p).w;
        dO += dS;
        ii += 1.0;
        if (dO > 120.0 || dS < 0.001) break;
    }
    return vec2(dO, ii);
}

vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
    return a + b * cos(6.28318 * (c * t + d));
}

vec3 shade(vec3 ro, vec3 rd, float t, float steps) {
    vec3 hitP = ro + rd * t;
    vec3 n = calcNormal(hitP);
    
    // Lighting
    vec3 lightDir = normalize(vec3(1.0, 1.5, -0.5));
    vec3 lightDir2 = normalize(vec3(-1.0, 0.5, 1.0));
    vec3 lightDir3 = normalize(vec3(0.0, -1.0, 0.5));
    float diff = max(dot(n, lightDir), 0.0);
    float diff2 = max(dot(n, lightDir2), 0.0);
    float diff3 = max(dot(n, lightDir3), 0.0);
    float spec = pow(max(dot(reflect(-lightDir, n), -rd), 0.0), 64.0);
    float spec2 = pow(max(dot(reflect(-lightDir2, n), -rd), 0.0), 32.0);
    float fres = pow(1.0 - max(dot(n, -rd), 0.0), 3.0);
    
    // Fractal-depth coloring: use trap orbit distance (approximated by position)
    float trap = length(hitP);
    float detail = sin(hitP.x * 20.0) * sin(hitP.y * 20.0) * sin(hitP.z * 20.0);
    
    // Iridescent color based on normal + view angle + fractal detail + time
    float colorParam = dot(n, rd) * 0.5 + 0.5 + time * 0.15 + trap * 0.3 + detail * 0.1;
    vec3 matCol = palette(colorParam, vec3(0.5), vec3(0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.1, 0.2));
    vec3 matCol2 = palette(colorParam + 0.3, vec3(0.5), vec3(0.5), vec3(1.0, 0.8, 0.6), vec3(0.3, 0.2, 0.2));
    vec3 matCol3 = palette(colorParam * 2.0 + 0.5, vec3(0.5), vec3(0.5), vec3(1.0, 1.0, 1.0), vec3(0.1, 0.4, 0.6));
    
    vec3 col = matCol * diff * 0.6 + matCol2 * diff2 * 0.25 + matCol3 * diff3 * 0.15;
    col += vec3(1.0, 0.95, 0.9) * spec * 1.5;
    col += matCol2 * spec2 * 0.5;
    col += palette(fres + time * 0.1 + trap * 0.2, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.8, 0.9, 0.3)) * fres * 0.6;
    
    // Edge glow based on step count (highlights fractal detail)
    float edgeGlow = steps / 100.0;
    col += palette(edgeGlow + time * 0.05, vec3(0.5), vec3(0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.33, 0.67)) * edgeGlow * 0.3;
    
    return col;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord.xy / iResolution.xy;
    vec2 p = (fragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
    p *= .3;
    // Camera
    float camDist = 4.0 + 1.0 * sin(time * 0.4);
    float camAngle = time * 0.25;
    vec3 ro = vec3(camDist * cos(camAngle), 1.0 * sin(time * 0.3), camDist * sin(camAngle));
    
    // Mouse control
    if (M.z > 0.0) {
        float mx = xm.x * 2.0 * pi;
        float my = (xm.y - 0.5) * pi;
        ro = vec3(camDist * cos(mx) * cos(my), camDist * sin(my), camDist * sin(mx) * cos(my));
    }
    
    vec3 ta = vec3(0.0);
    vec3 ww = normalize(ta - ro);
    vec3 uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0)));
    vec3 vv = cross(uu, ww);
    vec3 rd = normalize(p.x * uu + p.y * vv + 1.5 * ww);
    
    // Raymarch
    vec2 res = RM(ro, rd);
    float t = res.x;
    float steps = res.y;
    
    // Background - subtle gradient
    vec3 col = mix(vec3(0.02, 0.01, 0.05), vec3(0.08, 0.02, 0.12), p.y + 0.5);
    
    // Glow from steps (volumetric feel)
    float glow = steps / 100.0;
    vec3 glowCol = palette(glow + time * 0.1, vec3(0.5), vec3(0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.33, 0.67));
    vec3 bgGlow = glowCol * glow * 0.6;
    col += bgGlow;
    
    // Reflections via bounce loop
    vec3 curRo = ro;
    vec3 curRd = rd;
    float reflWeight = 1.0;
    vec3 accum = vec3(0.0);
    
    for (int bounce = 0; bounce < 3; bounce++) {
        vec2 bRes = (bounce == 0) ? res : RM(curRo, curRd);
        float bT = bRes.x;
        float bSteps = bRes.y;
        
        if (bT >= 120.0) {
            // Hit background
            vec3 bg = mix(vec3(0.02, 0.01, 0.05), vec3(0.08, 0.02, 0.12), curRd.y + 0.5);
            float bGlow = bSteps / 100.0;
            vec3 bGlowCol = palette(bGlow + time * 0.1, vec3(0.5), vec3(0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.33, 0.67));
            bg += bGlowCol * bGlow * 0.6;
            accum += reflWeight * bg;
            break;
        }
        
        vec3 hitP = curRo + curRd * bT;
        vec3 n = calcNormal(hitP);
        vec3 surfCol = shade(curRo, curRd, bT, bSteps);
        
        float fres = pow(1.0 - max(dot(n, -curRd), 0.0), 2.5);
        float reflAmount = mix(0.55, 0.95, fres); // High base reflectivity - metallic mirror
        
        // AO approximation
        float ao = 1.0 - bSteps / 100.0 * 0.5;
        accum += reflWeight * surfCol * (1.0 - reflAmount * 0.7) * ao;
        reflWeight *= reflAmount * ao;
        
        // Setup next bounce
        curRo = hitP + n * 0.01;
        curRd = reflect(curRd, n);
    }
    
    if (t < 120.0) {
        col = accum;
    } else {
        col = accum;
        float ao = 1.0 - glow * 0.5;
        col *= ao;
    }
    
    // Tone mapping + gamma
    col = col / (1.0 + col); // Reinhard
    col = pow(col, vec3(0.8)); // Slight gamma
    col *= 2.5;
    // Vignette
    float vig = 1.0 - 0.1 * dot(p, p);
    col *= vig;
    
    fragColor = vec4(col, 1.0);
}

Image

Not used

More shaders by scry

Browse all public shaders · All shaders by scry · ShaderKit home

Vibe Mode BETA
💰 ~0 credits
Uniforms
FPS: 0
Time: 0
Resolution: 0 x 0

Account

FPS: -- Time: -- --×-- 1x