Julia Fractal in GLSL

shaders

I wrote this for fun, it's mesmerizing to see the different fractals the different c values create.

It's probably not the most optimal code, don't look at it that way.

I also had a nastier bug probably due to rounding errors, but I didn't dig very deep on this issue.

Basically, when I used vec2 instead of computing the x,y values (the components of the complex number we're iterating on), the fractal appeared skewed. This could be to compiler optimizations, or some other rounding errors... To keep the shader correct I computed the values separately in the code below.

Make sure to play around with the settings, especially with the starting real and imaginary values! Here's the shader:

TIP: click on a slider and use the arrows to change the value, small changes can have big effects, so the mouse is not the best. Also, use Tab and Shift+Tab to switch between the controls!

hide controls

Controls

Code

Here's the fragment shader:

webgl
1precision highp float;
2
3uniform float u_time;
4uniform vec2 u_resolution;
5uniform vec2 u_mouse;
6
7uniform int u_iter_limit;
8uniform float u_c_real;
9uniform float u_c_imaginary;
10uniform float u_escape_radius;
11uniform float u_zoom;
12
13
14// constant because of WebGL's for loop constant expression constraint
15#define MAX_ITER 100000
16
17void main() {
18
19    vec4 FC = gl_FragCoord;
20    float R = u_escape_radius;
21    
22    vec2 r = u_resolution;
23    vec2 m = (u_mouse.xy / r.xy) * 2.0 - 1.0;
24    
25    vec2 c = vec2(u_c_real, u_c_imaginary);
26    
27    vec2 p = (FC.xy / r.xy) * 2.0 - 1.0;
28    float aspect = r.x / r.y;
29    p.x *= aspect;
30    c.x *= aspect;
31    p *= u_zoom;
32
33    float zx = p.x;
34    float zy = p.y;
35    float R2 = R*R;
36
37    int iterations = 0;
38
39    // go until u_iter_limit, MAX_ITER used because of WebGL constraints
40    for (int iter=0; iter < MAX_ITER; iter++)
41    { 
42        iterations = iter;
43
44        // z escapes, not part of the set, or we hit the iteration limit
45        if (zx*zx + zy*zy > R2 || iter > u_iter_limit)
46        {
47            break;
48        }
49
50        float temp = zx*zx - zy*zy;     
51        zy = 2. * zx * zy + c.y;
52        zx = temp + c.x;
53    }
54
55    // color based on how fast the value escaped the set
56    float iter_gradient = float(iterations) / float(u_iter_limit);
57
58    // color points in set black, otherwise white
59    // you can play around with coloring methods here, there are a lot of them
60    vec4 o = vec4(1.-iter_gradient, 1.-iter_gradient, 1.-iter_gradient, 1);
61
62    gl_FragColor = o;
63}