**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.

### Add required files

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

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.

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.

### 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:

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 z_{n} = z_{n-1}^{2} + c remains bounded as n goes to infinity. c = z_{0}

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:

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

### 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!

### 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.

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

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

### 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;`

to`vec2 c = vec2(-0.7,0.4);`

draws the following fractal:

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:

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 z
^{n}instead of z^{2}. 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

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

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

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.

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.

Great tutorial. Just a note:

u_sprite_size is vec2 not a float :]

https://www.shadertoy.com/view/MtfXzN