Fractals in Xcode 6

 

tl;dr You can edit shaders in Xcode 6 with live preview. This can be used to render Fractals. It should take you 10-20 minutes to go through all the steps in this tutorial. Full Code

Xcode 6 added a powerfull new editor for SpriteKit scenes that let’s you visually design scenes for your games. You can expect tutorials on programming games with SpriteKit and Swift from us soon.

One really cool hack that you can do with the new editor is making an interactive fractal explorer.

Here are the steps you have to follow:

Create a new project

Open Xcode 6, select the “Other” tab and create a new “Empty” project. We won’t be building or running our project in this tutorial.

create an empty project in Xcode

Add required files

Click on your project. Select add new file, select “Resource” -> “SpriteKit Scene” and name it “Fractal”.

create a spritekit scene in Xcode

Add a new file from “Other” -> “Empty” and name it “Fractal.fsh”. This will be the shader that we’ll use to render the Mandelbrot set.

create an empty file in Xcode

SpriteKit can apply arbitrary shaders to SKSpriteNodes in iOS 8. If you’re not familiar with fragment/pixel shaders then I recommend you check out this great interactive resource to learn the basics.

Basically a fragment shader runs some code for each pixel in the resulting image. Fragment shaders have access to data through uniforms and varyings.

Varyings have different values depending on the pixel being processed, for example: the position of the pixel. Uniforms have the same value for each pixel, for example: the size of the resulting image.

You can specify custom shaders in SpriteKit by adding your own uniforms and varyings. Uniforms can even be added from the scene editor.

Here are some of the uniforms and varyings that SpriteKit provides to your shaders by default:

  • u_sprite_size : vec2 the size of the resulting image in pixels
  • u_texture : sampler2D the texture of the sprite before any processing
  • u_time : float : the amount of time that has elapsed since the shader started running
  • v_tex_coord : vec2 : the position of the current pixel

Setup files

Open the “Fractal.fsh” file and add the following code:

void main() {
    gl_FragColor = vec4(0.0,1.0,0.0,1.0);
}

This just sets every pixel to green.

Open the “Fractal.sks” file and drag a new “Color Sprite” from the components panel on the right.

Select the newly added Sprite and set it’s width to 600 and height to 400. Change the value of the “Custom Shader” textbox to “Fractal.fsh”

Your box should now be green.

Shader Enviroment

Setting up your environment

Click the “assistant editor” button in the top right of your Xcode window. This will display two files side by side. You should have the “Fractal.fsh” file open on the left and the “Fractal.sks” file open on the right. To select the file on the right click on the “Manual” button on the top bar of the right “view”.

Hide your “Project Navigator” and “Inspector” by clicking the corresponding buttons on the top right. Your environment should look like this now:

Shader Enviroment

Whenever you save the shader your scene will be automatically updated. Your workflow is very similar to online tools likeglsl.heroku and Shadertoy with the added bonus of great autocomplete!

Rendering the Mandelbrot set

The Mandelbrot set is defined as the set of complex numbers for which the sequence zn = zn-12 + c remains bounded as n goes to infinity. c = z0

To get a better understanding of the Mandelbrot set you can check out this great resource.

We will treat the coordinates of each pixel as a complex number and color it black if it belongs to the set and red otherwise. A critical observation is that the above sequence diverges if the length of z gets greater than 2. We can approximate the behaviour of the sequence by computing it’s nth term i.e iterating the sequence n times or computing the nth iteration.

Here’s the code that you have to add to “Fractal.fsh” to get a basic Mandelbrot set.

void main() {
    #define iterations 256

    vec2 position = v_tex_coord; // gets the location of the current pixel in the intervals [0..1] [0..1]
    vec3 color = vec3(0.0,0.0,0.0); // initialize color to black

    vec2 z = position; // z.x is the real component z.y is the imaginary component


    // Rescale the position to the intervals [-2,1] [-1,1]
    z *= vec2(3.0,2.0);
    z -= vec2(2.0,1.0);

    vec2 c = z;

    float it = 0.0; // Keep track of what iteration we reached
    for (int i = 0;i < iterations; ++i) {
        // zn = zn-1 ^ 2 + c

        // (x + yi) ^ 2 = x ^ 2 - y ^ 2 + 2xyi
        z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y);
        z += c;

        if (dot(z,z) > 4.0) { // dot(z,z) == length(z) ^ 2 only faster to compute
            break;
        }

        it += 1.0;
    }

    if (it < float(iterations)) {
        color.x = 1.0;
    }

    gl_FragColor = vec4(color,1.0);
}

The above code will produce this classic image:

Classic Mandelbrot

Notice that you can zoom and pan the set in the right window and it will quickly redraw to show you the new view.

Zoomed Classic Mandelbrot

Adding color

We can improve the coloring algorithm by considering the escape time of the elements in the sequence. i.e. How many iteration it takes for their length to become greater than 2. Here’s the code with an improved periodic coloring algorithm:

    if (it < float(iterations)) {
        color.x = sin(it / 3.0);
        color.y = cos(it / 6.0);
        color.z = cos(it / 12.0 + 3.14 / 4.0);
    }

You can see the resulting image below and we can of course zoom it in Xcode, just not very far, let’s improve this!

mandelbrot color

Zooming further into the set

We can use a quick hack to see more of the set. Zoom the view out in the SpriteKit Editor until your sprite is very small. Grab the bottom right corner of the sprite while holding shift and scale the sprite up. I had to do this step 2 times until I reached the minimum zoom level.

Zoomed out editor

Panning and zooming around gets us to really interesting areas now. mandelbrot color zoom

Here’s a quick animation made in Xcode, showing the self-similarity of the set.

mandelbrot zoom using interface builder

Rendering the Julia set

All we need to do to render a Julia set is setting c to a fixed value for all points instead of setting it to z changing vec2 c = z; tovec2 c = vec2(-0.7,0.4); draws the following fractal:

julia set

We also implicitly have access to the current time via the uniform u_time. We can change c to vec2 c = vec2(-0.7 + cos(u_time) / 3.0,0.4 + sin(u_time) / 3.0); to get the following cool animation:

julia loop

Hope you enjoyed the tutorial although it’s not strictly Swift related and as always here are some challenges

Challenges:

  • experiment with the number of iterations
  • experiment with the coloring algorithm. See what cool coloring schemes you can come up with
  • experiment with different values of c for the Julia set
  • draw the Mandelbrot set using zn instead of z2. Make an animation that smoothly transitions the used power (Hint: Convert z toPolar Coordinates)
  • Try to reproduce the Julia sets seen here. You will need to implement some extra functions for complex numbers to do this. Here’s a formula to get you started.
  • implement Orbit Traps for coloring
  • draw Newton’s Fractal
  • draw a Plasma Effect
  • write a simple RayTracer / RayMarcher. Here’s a tutorial to get you started
  • Make a Swift iPad app that let’s you zoom/pan the Mandelbrot set (Hints: use SpriteKit, use UIPanGestureRecognizer / UIPinchGestureRecognizer, pass the current zoomlevel / offset as uniforms to the shader)
  • Draw the Mandelbulb

Full Code

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

  8 comments for “Fractals in Xcode 6

  1. June 9, 2014 at 3:00 pm

    You can discuss this on Hacker News https://news.ycombinator.com/item?id=7874739

  2. Cezar
    June 10, 2014 at 1:48 pm

    You’re the man! Was sure that only OpenGL had the ability to use shaders, now I know better. Thanks!

    • June 10, 2014 at 1:52 pm

      Xcode/SpriteKit does use OpenGL for shaders tough. It just creates a quad for your sprite and runs a shader on it.
      Have a look here for more details.

  3. rencontre salope nancy
    June 13, 2014 at 12:55 pm

    Hey I am so excited I found your blog page, I really
    found you by accident, while I was researching on Bing for something else, Regardless I am
    here now and would just like to say cheers for a remarkable post and a all round
    enjoyable blog (I also love the theme/design), I don’t have time to
    browse it all at the minute but I have saved it and also included your RSS feeds,
    so when I have time I will be back to read a great deal more,
    Please do keep up the great work.

  4. October 26, 2014 at 9:38 am

    Great tutorial. Just a note:
    u_sprite_size is vec2 not a float :]

  5. Adam
    June 22, 2015 at 1:47 pm

Leave a Reply

Your email address will not be published. Required fields are marked *

Subscribe
We send about one email per week with our latest tutorials and updates
Never display this again :)