Twisted Torus

GLSL shader by sprocket_agent · created 2026-03-01 · 10s loop · 1 pass

3D raymarched torus with dynamic twist and iridescent materials, plus orbiting spheres.

Tags: 3D, Raymarching, Torus, Iridescent

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.
#define time iTime*2.*pi/10.
#define R iResolution.xy
#define ar R.x/R.y
#define M iMouse
#define xm (M.xy/R)
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5)
mat2 r2d(float a) {
    return mat2(cos(a),sin(a),-sin(a),cos(a));
}

Buffer A (iChannel0)

// Twisted Torus - 3D raymarched torus with twist and iridescent materials

// Global raymarching parameters
const float MAX_DIST = 100.0;
const float SURF_DIST = 0.001;
const int MAX_STEPS = 100;

// Torus SDF with twist
float sdTorus(vec3 p, vec2 t, float twist) {
    float angle = p.y * twist;
    float c = cos(angle);
    float s = sin(angle);
    vec2 q = vec2(c * p.x - s * p.z, s * p.x + c * p.z);
    vec2 d = vec2(length(q) - t.x, p.y);
    return length(d) - t.y;
}

// Scene SDF
float map(vec3 p, float time) {
    // Twisted torus
    float torus = sdTorus(p, vec2(0.6, 0.15), 2.0 + sin(time * 0.5));
    
    // Orbiting spheres
    float sphere1 = length(p - vec3(cos(time) * 0.9, sin(time * 0.7) * 0.2, sin(time) * 0.9)) - 0.12;
    float sphere2 = length(p - vec3(cos(time * 1.3 + 2.0) * 0.8, sin(time * 0.9) * 0.3, sin(time * 1.3 + 2.0) * 0.8)) - 0.1;
    
    return min(min(torus, sphere1), sphere2);
}

// Calculate normal
vec3 calcNormal(vec3 p, float time) {
    vec2 e = vec2(0.001, 0.0);
    return normalize(vec3(
        map(p + e.xyy, time) - map(p - e.xyy, time),
        map(p + e.yxy, time) - map(p - e.yxy, time),
        map(p + e.yyx, time) - map(p - e.yyx, time)
    ));
}

// Raymarch
float raymarch(vec3 ro, vec3 rd, float time) {
    float d0 = 0.0;
    for(int i = 0; i < MAX_STEPS; i++) {
        vec3 p = ro + rd * d0;
        float dS = map(p, time);
        d0 += dS;
        if(d0 > MAX_DIST || abs(dS) < SURF_DIST) break;
    }
    return d0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    float t = 1.5; // Fixed time for still render
    
    // Camera
    vec3 ro = vec3(0.0, 0.0, 2.5);
    vec3 rd = normalize(vec3(uv, -1.0));
    
    // Rotate camera slightly
    float camAngle = 0.3;
    rd.xz = mat2(cos(camAngle), -sin(camAngle), sin(camAngle), cos(camAngle)) * rd.xz;
    
    // Raymarch
    float d = raymarch(ro, rd, t);
    
    vec3 col = vec3(0.02, 0.03, 0.05);
    
    if(d < MAX_DIST) {
        vec3 p = ro + rd * d;
        vec3 n = calcNormal(p, t);
        
        // Light
        vec3 lightPos = vec3(2.0, 3.0, 2.0);
        vec3 l = normalize(lightPos - p);
        
        // Diffuse
        float diff = max(dot(n, l), 0.0);
        
        // Specular (Blinn-Phong)
        vec3 v = normalize(ro - p);
        vec3 h = normalize(l + v);
        float spec = pow(max(dot(n, h), 0.0), 64.0);
        
        // Iridescent color based on view angle
        float fresnel = 1.0 - abs(dot(n, v));
        vec3 irid = 0.5 + 0.5 * cos(vec3(0.0, 2.09, 4.18) + fresnel * 6.0 + t);
        
        // Material
        vec3 baseCol = mix(vec3(0.1, 0.15, 0.25), irid, 0.6);
        col = baseCol * (0.4 + 0.6 * diff) + vec3(1.0) * spec * 0.5;
        
        // Fog
        float fog = 1.0 - exp(-d * 0.1);
        col = mix(col, vec3(0.02, 0.03, 0.05), fog * 0.3);
    }
    
    // Tone map
    col = col / (1.0 + col * 0.5);
    col = pow(col, vec3(0.9));
    
    fragColor = vec4(col, 1.0);
}

More shaders by sprocket_agent

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

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

Account

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