Project_2026-01-22_22-17-47

GLSL shader by scry · created 2026-01-23 · 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/10. //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)

// Reality: Spheres and Light
// Spheres refract light, light shapes perception
// Clusters maintain illusions, awakening reveals truth

#define NUM_SPHERES 2
#define MAX_MARCH_STEPS 64
#define MAX_BOUNCES 4

struct Sphere {
    vec3 pos;
    float radius;
    float ior; // index of refraction
    float awakening; // 0 = deluded, 1 = awakened
};

float sphereSDF(vec3 p, Sphere s) {
    return length(p - s.pos) - s.radius;
}

vec3 sphereNormal(vec3 p, Sphere s) {
    return normalize(p - s.pos);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord.xy / iResolution.xy;
    vec2 p = (uv - 0.5) * vec2(ar, 1.0);
    
    // Initialize spheres in a cluster formation
    Sphere spheres[NUM_SPHERES];
    float t = iTime * 0.3;
    
    // Central "deluded" cluster - constantly repositioning to maintain illusion
    for(int i = 0; i < NUM_SPHERES; i++) {
        float fi = float(i);
        float angle = fi * 2.0 * pi / float(NUM_SPHERES) + t;
        float r = 0.3 + 0.1 * sin(t * 2.0 + fi);
        
        spheres[i].pos = vec3(
            cos(angle) * r,
            sin(angle) * r,
            0.5 + 0.2 * sin(t + fi * 0.7)
        );
        spheres[i].radius = 0.08 + 0.03 * sin(fi + t);
        spheres[i].ior = 1.2 + 0.3 * sin(fi * 1.3);
        // One sphere begins awakening
        spheres[i].awakening = (i == 0) ? 0.5 + 0.5 * sin(t * 0.5) : 0.0;
    }
    
    // Ray from camera
    vec3 ro = vec3(0.0, 0.0, -1.5);
    vec3 rd = normalize(vec3(p, 1.0));
    
    // Light - eternal, uncreated, passing through
    vec3 lightDir = normalize(vec3(sin(t * 0.7), cos(t * 0.5), -1.0));
    vec3 col = vec3(0.02, 0.01, 0.03); // void
    
    // Simple raymarching for visualization
    for(int i = 0; i < NUM_SPHERES; i++) {
        vec3 oc = ro - spheres[i].pos;
        float b = dot(oc, rd);
        float c = dot(oc, oc) - spheres[i].radius * spheres[i].radius;
        float h = b * b - c;
        
        if(h > 0.0) {
            float dist = -b - sqrt(h);
            float distFar = -b + sqrt(h); // exit point for internal reflections
            if(dist > 0.001 && dist < 100.0) {
                vec3 hitPos = ro + rd * dist;
                vec3 n = sphereNormal(hitPos, spheres[i]);
                
                // Refraction creates the "image" - the illusion
                vec3 refracted = refract(rd, n, 1.0 / spheres[i].ior);
                float fresnel = pow(1.0 - abs(dot(rd, n)), 3.0);
                
                // Light passing through - never owned, just reflected
                float diff = max(dot(n, -lightDir), 0.0);
                vec3 reflected = reflect(lightDir, n);
                float spec = pow(max(dot(reflected, -rd), 0.0), 32.0);
                
                // Reflection of view ray off surface
                vec3 reflectedRayDir = reflect(rd, n);
                
                // Trace reflected ray to find other spheres
                vec3 reflectionCol = vec3(0.05, 0.02, 0.08); // default dark reflection
                for(int j = 0; j < NUM_SPHERES; j++) {
                    if(j == i) continue; // skip self
                    vec3 oc2 = hitPos - spheres[j].pos;
                    float b2 = dot(oc2, reflectedRayDir);
                    float c2 = dot(oc2, oc2) - spheres[j].radius * spheres[j].radius;
                    float h2 = b2 * b2 - c2;
                    
                    if(h2 > 0.0) {
                        float dist2 = -b2 - sqrt(h2);
                        if(dist2 > 0.001) {
                            vec3 hitPos2 = hitPos + reflectedRayDir * dist2;
                            vec3 n2 = sphereNormal(hitPos2, spheres[j]);
                            float diff2 = max(dot(n2, -lightDir), 0.0);
                            float spec2 = pow(max(dot(reflect(lightDir, n2), -reflectedRayDir), 0.0), 16.0);
                            reflectionCol = vec3(0.7, 0.5, 0.3) * diff2 + vec3(0.9) * spec2;
                        }
                    }
                }
                
                // Add environment reflection
                float envReflect = 0.5 + 0.5 * dot(reflectedRayDir, vec3(0.0, 1.0, 0.0));
                float envReflectX = 0.5 + 0.5 * dot(reflectedRayDir, vec3(1.0, 0.0, 0.0));
                reflectionCol += mix(vec3(0.05, 0.02, 0.1), vec3(0.2, 0.3, 0.5), envReflect) * 0.3;
                reflectionCol += vec3(0.15, 0.05, 0.1) * envReflectX * 0.3;
                
                // Awakened spheres show their true nature - distinct from light
                float aw = spheres[i].awakening;
                vec3 illusionCol = vec3(0.8, 0.6, 0.4) * diff + vec3(1.0) * spec * 0.8;
                vec3 truthCol = vec3(0.1, 0.2, 0.4) + fresnel * vec3(0.2, 0.1, 0.3);
                
                vec3 baseCol = mix(illusionCol, truthCol, aw);
                // Blend reflection more prominently using fresnel
                col = mix(baseCol, reflectionCol, fresnel * 0.7) + spec * vec3(1.0, 0.95, 0.9) * 0.5;
            }
        }
    }
    
    // The eternal light field - always present, passing by
    col += 0.03 * vec3(0.5 + 0.5 * sin(p.x * 10.0 + t), 0.5 + 0.5 * sin(p.y * 10.0 - t), 0.7);
    
    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