Mandelbrot Set Shader

The Mandelbrot set is a fractal. Fractals are mathematical sets that have a repeating pattern at every scale. For more information look at the bottom of this post.

Due to the intensive native of computing the Mandelbrot set, computing it with the CPU is not fast enough to do more than just render an image to the screen. However using the GPU you can render it much faster and at higher resolutions. The following code was written in processing and GLSL to render the fractal to the screen and allow you to move around in real time.

PShader fractal;
float xC = 0;
float yC = 0;
float zoom = 1;
boolean[] keyDown = new boolean[8];
float zoomSpeed = 0.01;
float movementSpeed = 0.1;
float heightF;
float widthF;

void setup() {
  size(960, 640, P3D);
  fractal = loadShader("shaderFrag.glsl", "defaultVert.glsl");
  heightF = height;
  widthF = width;
  //set shader variables
  fractal.set("windowSize", widthF, heightF);
  fractal.set("cameraPos", xC, yC);
  fractal.set("zoom", zoom);
}

void draw() {
  background(0);
  //set which shader
  shader(fractal);
  //render blank box to use the shader on
  rect(0,0,width,height);
  //handle movement
  movement();
  
  //set shader variables
  fractal.set("windowSize", widthF, heightF);
  fractal.set("cameraPos", xC, yC);
  fractal.set("zoom", zoom);
}


 private void movement() {
  if (keyDown[0] == true) {
    yC += movementSpeed * zoom;
  }
  if (keyDown[1] == true) {
    yC -= movementSpeed * zoom;
  }
  if (keyDown[2] == true) { 
    xC -= movementSpeed * zoom;
  }
  if (keyDown[3] == true) { 
    xC += movementSpeed * zoom;
  }
  if (keyDown[4] == true) { 
    zoom -= zoomSpeed * zoom;
  }
  if (keyDown[5] == true) { 
    zoom += zoomSpeed * zoom;
  }
}

public void keyPressed() {
  if (key == 'w' || (key == CODED && keyCode == UP)) {
    keyDown[0] = true;
  }
  if (key == 's' || (key == CODED && keyCode == DOWN)) {
    keyDown[1] = true;
  }
  if (key == 'a' || (key == CODED && keyCode == LEFT)) {
    keyDown[2] = true;
  }
  if (key == 'd' || (key == CODED && keyCode == RIGHT)) {
    keyDown[3] = true;
  }
  if (key == '=') {
    keyDown[4] = true;
  }
  if (key == '-') {
    keyDown[5] = true;
  }
}

public void keyReleased() {
  if (key == 'w' || (key == CODED && keyCode == UP)) {
    keyDown[0] = false;
  }
  if (key == 's' || (key == CODED && keyCode == DOWN)) {
    keyDown[1] = false;
  }
  if (key == 'a' || (key == CODED && keyCode == LEFT)) {
    keyDown[2] = false;
  }
  if (key == 'd' || (key == CODED && keyCode == RIGHT)) {
    keyDown[3] = false;
  }
  if (key == '=') {
    keyDown[4] = false;
  }
  if (key == '-') {
    keyDown[5] = false;
  }
}

Fragment Shader (where Mandelbrot is rendered)

precision highp float;

uniform sampler2D texture;
uniform vec2 windowSize;
uniform vec2 cameraPos;
uniform float zoom;

varying vec4 vertColor;
varying vec4 vertTexCoord;
varying vec4 pos;

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

void main() {
    vec3 color = vec3(0,0,0);
	vec2 pixel = (pos.xy / windowSize) * zoom; 
    double x0 = ((3.5 * pixel.x)) + (cameraPos.x);
    double y0 = ((2.0 * pixel.y)) + (cameraPos.y);
    double x = 0.0;
    double y = 0.0;
    int iteration = 0;
    int max_iteration = 250;
	double xtemp = 0.0;
    while (x * x + y * y < 4  &&  iteration < max_iteration) {
         xtemp = x*x - y*y + x0;
         y = 2.0 * x*y + y0;
         x = xtemp;
         iteration = iteration + 1;
    }
    if (iteration != max_iteration) {
		  float tmp = float(iteration) / float(max_iteration);
		  color = hsv2rgb(vec3(tmp * 10, 1.0, 1.0));
    }
    gl_FragColor = vec4(color.r, color.g, color.b, 1.0);
}

Vertex Shader

#define PROCESSING_COLOR_SHADER

uniform mat4 transform;
uniform mat4 texMatrix;

attribute vec4 vertex;
attribute vec4 color;
attribute vec2 texCoord;

varying vec4 vertColor;
varying vec4 vertTexCoord;
varying vec4 pos;

void main() {
    gl_Position = transform * vertex;
    pos = transform * vertex;
    vertColor = color;
    vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}

Fractal: Click Here

Mandelbrot Set: Click Here 

Processing Shaders: Click Here