Julia Orbit Traps

Rendering the Julia Fractal but via orbit traps.

Gallery

Meta

2022 note: I've changed the colour scheme of the shader.

Shader

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#define MAX_ITER 500
#define INF 100.

#define col1 vec3(1., .3, .4)
#define col2 vec3(.4, 1., .2)
#define col3 vec3(.3, .4, 1.)

float trap(in vec2 uv, in vec2 p) {
    float txt = texture(iChannel0, uv).x;
    return distance(uv, p) * (txt + 1.);
}

float shake(float off)
{
    return sin(iTime*.5 + off) + .2*sin(iTime*.7+.5 + off*.3) + .1*sin(iTime+.3 + off*.7);
}

vec3 render(in vec2 uv)
{
    float s = .13*sin(iTime*.3);
    vec2 c = vec2(-0.77568377,0.134646737) + s*s;
    int i = 0;
    
    float mdist1 = INF; float mdist2 = INF; float mdist3 = INF;
    float dist1, dist2, dist3; 
    for (i=0; i<MAX_ITER; ++i)
    {
        if (uv.x*uv.x + uv.y*uv.y > 4.) break;
        
        uv = vec2(uv.x*uv.x - uv.y*uv.y, 2.*uv.x*uv.y) + c;
        
        dist1 = trap(uv, vec2(0.,0.));
        dist2 = trap(uv, vec2(0.,.5));
        dist3 = trap(uv, vec2(.5,0.));
        
        if (mdist1 > dist1) mdist1 = dist1;
        if (mdist2 > dist2) mdist2 = dist2;
        if (mdist3 > dist3) mdist3 = dist3;
    }
    
    // Compute smooth iteration:
    // https://www.iquilezles.org/www/articles/mset_smooth/mset_smooth.htm
    float iter = float(i) - log2(log2(dot(uv,uv))) + 4.0;
    iter /= float(MAX_ITER);
    
    vec3 col = mdist1*col1 + mdist2*col2 + mdist3*col3;
    col *= (cos(iter*1.57)+.6)/2.;
    col *= col;
    col = 1.-col;
    
    return clamp(vec3(col), 0.,1.);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float s1, s2;
    s1 = shake(0.); s2 = shake(1.5);
    
    vec2 uv = (1.7 + .1*s1)*(fragCoord/iResolution.xy - .5);
    uv.x *= iResolution.x/iResolution.y;
    
    vec3 col = render(uv);
    vec3 w = vec3(2.,.2,.5);
    col += vec3(.1,-.3,.2)*(length(w) - dot(col, w));
    col = pow(col, vec3(1., 1.5, 1.9));
    
    fragColor = vec4(col, 1.);
}