Author

Steve Trettel

Published

January 2026

1 Day 5 Shaders

Complete, runnable shaders for each demo in the notes.


1.1 ray-visualization

struct Ray {
    vec3 origin;
    vec3 dir;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    vec3 color = ray.dir * 0.5 + 0.5;
    fragColor = vec4(color, 1.0);
}

1.2 sphere-flat

struct Ray {
    vec3 origin;
    vec3 dir;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

float intersectSphere(Ray ray, vec3 center, float radius) {
    vec3 delta = ray.origin - center;
    
    float b = dot(delta, ray.dir);
    float c = dot(delta, delta) - radius * radius;
    float discriminant = b * b - c;
    
    if (discriminant < 0.0) return -1.0;
    
    float sqrtDisc = sqrt(discriminant);
    float t1 = -b - sqrtDisc;
    float t2 = -b + sqrtDisc;
    
    if (t1 > 0.0) return t1;
    if (t2 > 0.0) return t2;
    return -1.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    
    float t = intersectSphere(ray, vec3(0.0, 0.0, -3.0), 1.0);
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (t > 0.0) color = vec3(1.0, 0.0, 0.0);
    
    fragColor = vec4(color, 1.0);
}

1.3 sphere-normals

struct Ray {
    vec3 origin;
    vec3 dir;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

float intersectSphere(Ray ray, vec3 center, float radius) {
    vec3 delta = ray.origin - center;
    
    float b = dot(delta, ray.dir);
    float c = dot(delta, delta) - radius * radius;
    float discriminant = b * b - c;
    
    if (discriminant < 0.0) return -1.0;
    
    float sqrtDisc = sqrt(discriminant);
    float t1 = -b - sqrtDisc;
    float t2 = -b + sqrtDisc;
    
    if (t1 > 0.0) return t1;
    if (t2 > 0.0) return t2;
    return -1.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    
    vec3 sphereCenter = vec3(0.0, 0.0, -3.0);
    float sphereRadius = 1.0;
    
    float t = intersectSphere(ray, sphereCenter, sphereRadius);
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (t > 0.0) {
        vec3 hitPoint = ray.origin + t * ray.dir;
        vec3 normal = (hitPoint - sphereCenter) / sphereRadius;
        color = normal * 0.5 + 0.5;
    }
    
    fragColor = vec4(color, 1.0);
}

1.4 sphere-lit

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

Hit intersectSphere(Ray ray, vec3 center, float radius, vec3 color) {
    Hit hit;
    hit.t = -1.0;
    
    vec3 delta = ray.origin - center;
    float b = dot(delta, ray.dir);
    float c = dot(delta, delta) - radius * radius;
    float discriminant = b * b - c;
    
    if (discriminant < 0.0) return hit;
    
    float sqrtDisc = sqrt(discriminant);
    float t1 = -b - sqrtDisc;
    float t2 = -b + sqrtDisc;
    
    if (t1 > 0.0) hit.t = t1;
    else if (t2 > 0.0) hit.t = t2;
    else return hit;
    
    hit.point = ray.origin + hit.t * ray.dir;
    hit.normal = (hit.point - center) / radius;
    hit.color = color;
    return hit;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    Hit hit = intersectSphere(ray, vec3(0.0, 0.0, -3.0), 1.0, vec3(1.0, 0.0, 0.0));
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (hit.t > 0.0) {
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.5 sphere-orbit

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

Hit intersectSphere(Ray ray, vec3 center, float radius, vec3 color) {
    Hit hit;
    hit.t = -1.0;
    
    vec3 delta = ray.origin - center;
    float b = dot(delta, ray.dir);
    float c = dot(delta, delta) - radius * radius;
    float discriminant = b * b - c;
    
    if (discriminant < 0.0) return hit;
    
    float sqrtDisc = sqrt(discriminant);
    float t1 = -b - sqrtDisc;
    float t2 = -b + sqrtDisc;
    
    if (t1 > 0.0) hit.t = t1;
    else if (t2 > 0.0) hit.t = t2;
    else return hit;
    
    hit.point = ray.origin + hit.t * ray.dir;
    hit.normal = (hit.point - center) / radius;
    hit.color = color;
    return hit;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 5.0);
    
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    Hit hit = intersectSphere(ray, vec3(0.0), 1.0, vec3(1.0, 0.0, 0.0));
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (hit.t > 0.0) {
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.6 torus-analytical

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

// Torus intersection by Inigo Quilez
// https://iquilezles.org/articles/intersectors/
float intersectTorusRaw(Ray ray, vec2 tor) {
    float po = 1.0;
    float Ra2 = tor.x * tor.x;
    float ra2 = tor.y * tor.y;
    
    float m = dot(ray.origin, ray.origin);
    float n = dot(ray.origin, ray.dir);
    
    float h = n*n - m + (tor.x + tor.y) * (tor.x + tor.y);
    if (h < 0.0) return -1.0;
    
    float k = (m - ra2 - Ra2) / 2.0;
    float k3 = n;
    float k2 = n*n + Ra2*ray.dir.y*ray.dir.y + k;
    float k1 = k*n + Ra2*ray.origin.y*ray.dir.y;
    float k0 = k*k + Ra2*ray.origin.y*ray.origin.y - Ra2*ra2;
    
    if (abs(k3*(k3*k3 - k2) + k1) < 0.01) {
        po = -1.0;
        float tmp = k1; k1 = k3; k3 = tmp;
        k0 = 1.0/k0;
        k1 = k1*k0;
        k2 = k2*k0;
        k3 = k3*k0;
    }
    
    float c2 = 2.0*k2 - 3.0*k3*k3;
    float c1 = k3*(k3*k3 - k2) + k1;
    float c0 = k3*(k3*(-3.0*k3*k3 + 4.0*k2) - 8.0*k1) + 4.0*k0;
    
    c2 /= 3.0;
    c1 *= 2.0;
    c0 /= 3.0;
    
    float Q = c2*c2 + c0;
    float R = 3.0*c0*c2 - c2*c2*c2 - c1*c1;
    
    float h2 = R*R - Q*Q*Q;
    float z = 0.0;
    
    if (h2 < 0.0) {
        float sQ = sqrt(Q);
        z = 2.0*sQ*cos(acos(R/(sQ*Q)) / 3.0);
    } else {
        float sQ = pow(sqrt(h2) + abs(R), 1.0/3.0);
        z = sign(R)*abs(sQ + Q/sQ);
    }
    
    z = c2 - z;
    
    float d1 = z - 3.0*c2;
    float d2 = z*z - 3.0*c0;
    
    if (abs(d1) < 1.0e-4) {
        if (d2 < 0.0) return -1.0;
        d2 = sqrt(d2);
    } else {
        if (d1 < 0.0) return -1.0;
        d1 = sqrt(d1/2.0);
        d2 = c1/d1;
    }
    
    float result = 1e20;
    
    h2 = d1*d1 - z + d2;
    if (h2 > 0.0) {
        h2 = sqrt(h2);
        float t1 = -d1 - h2 - k3;
        float t2 = -d1 + h2 - k3;
        t1 = (po < 0.0) ? 2.0/t1 : t1;
        t2 = (po < 0.0) ? 2.0/t2 : t2;
        if (t1 > 0.0) result = t1;
        if (t2 > 0.0) result = min(result, t2);
    }
    
    h2 = d1*d1 - z - d2;
    if (h2 > 0.0) {
        h2 = sqrt(h2);
        float t1 = d1 - h2 - k3;
        float t2 = d1 + h2 - k3;
        t1 = (po < 0.0) ? 2.0/t1 : t1;
        t2 = (po < 0.0) ? 2.0/t2 : t2;
        if (t1 > 0.0) result = min(result, t1);
        if (t2 > 0.0) result = min(result, t2);
    }
    
    if (result > 1e10) return -1.0;
    return result;
}

vec3 torusNormal(vec3 p, vec2 tor) {
    float R = tor.x;
    float k = sqrt(p.x*p.x + p.z*p.z);
    return normalize(vec3(p.x * (1.0 - R/k), p.y, p.z * (1.0 - R/k)));
}

Hit intersectTorus(Ray ray, vec2 tor, vec3 color) {
    Hit hit;
    hit.t = intersectTorusRaw(ray, tor);
    if (hit.t > 0.0) {
        hit.point = ray.origin + hit.t * ray.dir;
        hit.normal = torusNormal(hit.point, tor);
        hit.color = color;
    }
    return hit;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 4.0);
    
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    // Torus with major radius 1.0, minor radius 0.4
    Hit hit = intersectTorus(ray, vec2(1.0, 0.4), vec3(0.0, 0.7, 1.0));
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (hit.t > 0.0) {
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.7 sdf-circle-2d

float sdCircle(vec2 p, float r) {
    return length(p) - r;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 2.0;
    
    float d = sdCircle(p, 1.0);
    
    // Color by sign: blue inside, orange outside
    vec3 color;
    if (d < 0.0) {
        color = vec3(0.2, 0.4, 0.8);  // inside: blue
    } else {
        color = vec3(0.9, 0.6, 0.2);  // outside: orange
    }
    
    // Darken near the boundary
    color *= 1.0 - exp(-6.0 * abs(d));
    
    // Contour lines
    float contour = abs(fract(d * 4.0 + 0.5) - 0.5);
    color = mix(vec3(1.0), color, smoothstep(0.0, 0.05, contour));
    
    // Highlight the zero level set
    color = mix(vec3(1.0), color, smoothstep(0.0, 0.02, abs(d)));
    
    fragColor = vec4(color, 1.0);
}

1.8 sdf-box-2d

float sdBox(vec2 p, vec2 halfSize) {
    vec2 d = abs(p) - halfSize;
    return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 2.0;
    
    float d = sdBox(p, vec2(0.8, 0.5));
    
    // Color by sign: blue inside, orange outside
    vec3 color;
    if (d < 0.0) {
        color = vec3(0.2, 0.4, 0.8);  // inside: blue
    } else {
        color = vec3(0.9, 0.6, 0.2);  // outside: orange
    }
    
    // Darken near the boundary
    color *= 1.0 - exp(-6.0 * abs(d));
    
    // Contour lines
    float contour = abs(fract(d * 4.0 + 0.5) - 0.5);
    color = mix(vec3(1.0), color, smoothstep(0.0, 0.05, contour));
    
    // Highlight the zero level set
    color = mix(vec3(1.0), color, smoothstep(0.0, 0.02, abs(d)));
    
    fragColor = vec4(color, 1.0);
}

1.9 raymarch-sphere

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

float sceneSDF(vec3 p) {
    return length(p) - 1.0;  // Unit sphere at origin
}

vec3 calcNormal(vec3 p) {
    float eps = 0.001;
    return normalize(vec3(
        sceneSDF(p + vec3(eps, 0, 0)) - sceneSDF(p - vec3(eps, 0, 0)),
        sceneSDF(p + vec3(0, eps, 0)) - sceneSDF(p - vec3(0, eps, 0)),
        sceneSDF(p + vec3(0, 0, eps)) - sceneSDF(p - vec3(0, 0, eps))
    ));
}

float raymarch(Ray ray) {
    float t = 0.0;
    
    for (int i = 0; i < 100; i++) {
        vec3 p = ray.origin + t * ray.dir;
        float d = sceneSDF(p);
        
        if (d < 0.001) return t;
        
        t += d;
        
        if (t > 100.0) return -1.0;
    }
    
    return -1.0;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 5.0);
    
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    float t = raymarch(ray);
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (t > 0.0) {
        vec3 p = ray.origin + t * ray.dir;
        vec3 normal = calcNormal(p);
        
        Hit hit;
        hit.t = t;
        hit.point = p;
        hit.normal = normal;
        hit.color = vec3(1.0, 0.0, 0.0);
        
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.10 raymarch-torus

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

float sceneSDF(vec3 p) {
    vec2 tor = vec2(1.0, 0.4);  // major radius, minor radius
    vec2 q = vec2(length(p.xz) - tor.x, p.y);
    return length(q) - tor.y;
}

vec3 calcNormal(vec3 p) {
    float eps = 0.001;
    return normalize(vec3(
        sceneSDF(p + vec3(eps, 0, 0)) - sceneSDF(p - vec3(eps, 0, 0)),
        sceneSDF(p + vec3(0, eps, 0)) - sceneSDF(p - vec3(0, eps, 0)),
        sceneSDF(p + vec3(0, 0, eps)) - sceneSDF(p - vec3(0, 0, eps))
    ));
}

float raymarch(Ray ray) {
    float t = 0.0;
    
    for (int i = 0; i < 100; i++) {
        vec3 p = ray.origin + t * ray.dir;
        float d = sceneSDF(p);
        
        if (d < 0.001) return t;
        
        t += d;
        
        if (t > 100.0) return -1.0;
    }
    
    return -1.0;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 4.0);
    
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    float t = raymarch(ray);
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (t > 0.0) {
        vec3 p = ray.origin + t * ray.dir;
        vec3 normal = calcNormal(p);
        
        Hit hit;
        hit.t = t;
        hit.point = p;
        hit.normal = normal;
        hit.color = vec3(0.0, 0.7, 1.0);
        
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.11 scene-multi

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

float sdTorus(vec3 p, vec2 tor) {
    vec2 q = vec2(length(p.xz) - tor.x, p.y);
    return length(q) - tor.y;
}

float sceneSDF(vec3 p) {
    float sphere = length(p - vec3(-1.5, 0.0, 0.0)) - 1.0;
    float torus = sdTorus(p - vec3(1.5, 0.0, 0.0), vec2(0.8, 0.3));
    float ground = p.y + 1.0;
    return min(sphere, min(torus, ground));
}

vec3 calcNormal(vec3 p) {
    float eps = 0.001;
    return normalize(vec3(
        sceneSDF(p + vec3(eps, 0, 0)) - sceneSDF(p - vec3(eps, 0, 0)),
        sceneSDF(p + vec3(0, eps, 0)) - sceneSDF(p - vec3(0, eps, 0)),
        sceneSDF(p + vec3(0, 0, eps)) - sceneSDF(p - vec3(0, 0, eps))
    ));
}

float raymarch(Ray ray) {
    float t = 0.0;
    
    for (int i = 0; i < 100; i++) {
        vec3 p = ray.origin + t * ray.dir;
        float d = sceneSDF(p);
        
        if (d < 0.001) return t;
        
        t += d;
        
        if (t > 100.0) return -1.0;
    }
    
    return -1.0;
}

vec3 shade(Hit hit, Light light, vec3 viewDir) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 32.0);
    
    vec3 diff = hit.color * light.color * diffuse;
    vec3 spec = light.color * specular * 0.5;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 6.0);
    
    Light light = Light(normalize(vec3(1.0, 1.0, 1.0)), vec3(1.0));
    
    float t = raymarch(ray);
    
    vec3 color = vec3(0.1, 0.1, 0.2);
    if (t > 0.0) {
        vec3 p = ray.origin + t * ray.dir;
        vec3 normal = calcNormal(p);
        
        Hit hit;
        hit.t = t;
        hit.point = p;
        hit.normal = normal;
        hit.color = vec3(0.9, 0.5, 0.2);
        
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light, -ray.dir);
    }
    
    fragColor = vec4(color, 1.0);
}

1.12 barth-sextic-final

struct Ray {
    vec3 origin;
    vec3 dir;
};

struct Hit {
    float t;
    vec3 point;
    vec3 normal;
    vec3 color;
};

struct Light {
    vec3 dir;
    vec3 color;
};

Ray generateRay(vec2 fragCoord) {
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    
    float fov = 90.0;
    float f = 1.0 / tan(radians(fov) / 2.0);
    
    Ray ray;
    ray.origin = vec3(0.0);
    ray.dir = normalize(vec3(uv, -f));
    return ray;
}

mat3 rotateX(float a) {
    float c = cos(a), s = sin(a);
    return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}

mat3 rotateY(float a) {
    float c = cos(a), s = sin(a);
    return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}

Ray orbitCamera(Ray ray, float distance) {
    vec2 mouse = iMouse.xy / iResolution.xy;
    float angleY = (mouse.x - 0.5) * 6.28;
    float angleX = (0.5 - mouse.y) * 3.14;
    
    mat3 rot = rotateX(angleX) * rotateY(angleY);
    ray.origin = rot * vec3(0.0, 0.0, distance);
    ray.dir = rot * ray.dir;
    return ray;
}

float polynomial(vec3 p) {
    float phi = (1.0 + sqrt(5.0)) / 2.0;
    float phi2 = phi * phi;
    
    float x2 = p.x * p.x, y2 = p.y * p.y, z2 = p.z * p.z;
    
    float a = (phi2 * x2 - y2) * (phi2 * y2 - z2) * (phi2 * z2 - x2);
    float b = (x2 + y2 + z2 - 1.0);
    
    return 4.0 * a - (1.0 + 2.0 * phi) * b * b;
}

vec3 gradient(vec3 p) {
    float eps = 0.001;
    return vec3(
        polynomial(p + vec3(eps, 0, 0)) - polynomial(p - vec3(eps, 0, 0)),
        polynomial(p + vec3(0, eps, 0)) - polynomial(p - vec3(0, eps, 0)),
        polynomial(p + vec3(0, 0, eps)) - polynomial(p - vec3(0, 0, eps))
    ) / (2.0 * eps);
}

float sdBarth(vec3 p) {
    // Rotate the Barth surface
    mat3 spin = rotateY(iTime * 0.3);
    p = spin * p;
    
    // Bounding sphere
    float bounds = length(p) - 2.5;
    if (bounds > 0.01) return bounds;
    
    // Distance estimate for algebraic variety
    float f = polynomial(p);
    vec3 g = gradient(p);
    float glen = length(g);
    if (glen < 0.001) return 0.1;
    return 0.5 * abs(f) / glen;
}

float sceneSDF(vec3 p) {
    float barth = sdBarth(p);
    float floor = p.y + 1.8;
    return min(barth, floor);
}

vec3 sceneColor(vec3 p) {
    float barth = sdBarth(p);
    float floor = p.y + 1.8;
    
    if (barth < floor) {
        return vec3(0.9, 0.7, 0.5);  // Barth: gold
    }
    return vec3(0.3, 0.3, 0.35);     // Floor: gray
}

vec3 calcNormal(vec3 p) {
    float eps = 0.001;
    return normalize(vec3(
        sceneSDF(p + vec3(eps, 0, 0)) - sceneSDF(p - vec3(eps, 0, 0)),
        sceneSDF(p + vec3(0, eps, 0)) - sceneSDF(p - vec3(0, eps, 0)),
        sceneSDF(p + vec3(0, 0, eps)) - sceneSDF(p - vec3(0, 0, eps))
    ));
}

float raymarch(Ray ray) {
    float t = 0.0;
    
    for (int i = 0; i < 200; i++) {
        vec3 p = ray.origin + t * ray.dir;
        float d = sceneSDF(p);
        
        if (d < 0.0005) return t;
        
        t += d;
        
        if (t > 100.0) return -1.0;
    }
    
    return -1.0;
}

float shadow(vec3 origin, vec3 lightDir, float maxDist) {
    float t = 0.02;
    for (int i = 0; i < 50; i++) {
        float d = sceneSDF(origin + lightDir * t);
        if (d < 0.001) return 0.0;
        t += d;
        if (t > maxDist) break;
    }
    return 1.0;
}

vec3 shade(Hit hit, Light light, vec3 viewDir, float shadowFactor) {
    float diffuse = max(0.0, dot(hit.normal, light.dir));
    vec3 reflected = reflect(-light.dir, hit.normal);
    float specular = pow(max(0.0, dot(reflected, viewDir)), 64.0);
    
    vec3 diff = hit.color * light.color * diffuse * shadowFactor;
    vec3 spec = light.color * specular * 0.5 * shadowFactor;
    return diff + spec;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    Ray ray = generateRay(fragCoord);
    ray = orbitCamera(ray, 5.0);
    
    // Two colored lights
    Light light1 = Light(normalize(vec3(1.0, 2.0, 1.0)), vec3(1.0, 0.8, 0.6));
    Light light2 = Light(normalize(vec3(-1.0, 1.0, -0.5)), vec3(0.3, 0.4, 0.8));
    
    float t = raymarch(ray);
    
    vec3 color = vec3(0.05, 0.05, 0.1);
    if (t > 0.0) {
        vec3 p = ray.origin + t * ray.dir;
        vec3 normal = calcNormal(p);
        
        // Flip normal if facing away from camera (for Barth surface)
        if (dot(normal, ray.dir) > 0.0) normal = -normal;
        
        Hit hit;
        hit.t = t;
        hit.point = p;
        hit.normal = normal;
        hit.color = sceneColor(p);
        
        float shadow1 = shadow(p, light1.dir, 20.0);
        float shadow2 = shadow(p, light2.dir, 20.0);
        
        vec3 ambient = hit.color * 0.1;
        color = ambient + shade(hit, light1, -ray.dir, shadow1) + shade(hit, light2, -ray.dir, shadow2);
    }
    
    fragColor = vec4(color, 1.0);
}