loading...

A Fractal Playground with Processing

zanehelton profile image Zane Helton Updated on ・4 min read

Sooo Processing is pretty cool. I first came across it when Daniel Shiffman was recommended in my YouTube feed and I've had a lot of fun with it since. In short: it's a Java sketchbook that allows anyone to create interactive and visual sketches in 2D / 3D space. It's super powerful, and super easy to get started with.

Above is a bare bones drawing program created in just a few lines of code. Processing has a lot more to offer, but in this post I'm going to walk you through making fractals from simple shapes.

But before we start frantically searching StackOverflow for Java compiler errors, let's talk about how a fractal is made.


Triangle de Sierpinski

A fractal is a simple pattern driven by recursion (don't panic).
Consider the recursive image:

Take a second to think about the ways you might implement something like this. What determines the next step in the sequence? How can we make sure the squares don't overlap?

Once you've thought about how you would do it, toss it, because unless you said "move the origin at every step" it's probably going to be a hassle. The trick to recursive functions in Processing is to keep track of your origin. Here's the same sketch from before, but with a red circle to follow the origin at every iteration.

In Processing, the function to move the origin is translate(...), and translate(...) is a function that shifts the origin relative to it's previous position. For example: translate(3, 9) would move the origin 3 to the right and 9 down.

Let's code

The scaling squares example from before is a reasonable first feat, so that's where we'll start.

void setup() {
  size(1000, 250);
}

void draw() {
  scalingSquares(200); // we'll define this function next
                       // it'll be called once per frame
}

These two functions are the heart and soul of your Processing sketches, so try to keep them clean.

We're going to put the code responsible for drawing the squares into it's own function called scalingSquares(...).

void scalingSquares(float n) {
  rect(0, 0, n, n);
  translate(n + 5, n / 8);
}

If you tried this with 200 as the argument in draw(), expect to see:

We have everything needed to complete the scaling squares except the key ingredient...recursion!

By adding these two lines...

void scalingSquares(float n) {
+ if (n < 30) return;       // don't draw squares that are less than 30x30
  rect(0, 0, n, n);         //
  translate(n + 5, n / 8);  // offset each square by itself + 5px
                            // and move each square down 1/8 to vertically align
                            //
+ scalingSquares(n * 0.75); // each square is 75% the size of the one before it
}

We've got our scaling squares functionality using a recursive function.

An important thing to note is the value passed into scalingSquares(...) within scalingSquares(...). It's the original argument multiplied by 0.75 to reduce the scale factor going into the recursive function until it's less than 30 pixels.

Better fractals?

If you've spent any amount of time on the Internet, you know that's hardly a fractal. To create more complex fractals, adding pushMatrix() and popMatrix() to your arsenal would be wise. pushMatrix() saves the current origin and the properties of the grid to an off-screen stack and popMatrix() restores the origin and grid to the most recently stored. Think of pushMatrix() as a Save function and popMatrix() as the Load function for the grid.

void setup() {
  size(700, 700);
}

void draw() {
  background(255);

  noFill();

  translate(width / 2, height / 2); // move origin to middle of canvas
  draw_fractal(500);
}

void draw_fractal(float r) {
  ellipse(0, 0, r, r);  // draw origin circle

  if (r < 100)          // don't draw circles smaller than 100x100
    return;

  stroke(255, 0, 0);    // red circles
  pushMatrix();         // save the origin, we're about to change it
  translate(0, -r / 4); // move the origin straight down to the 1/4 mark
  draw_fractal(r / 2);  // restart the process at half the scale
  popMatrix();

  stroke(0, 0, 255);    // blue circles
  pushMatrix();
  translate(0, r / 4);
  draw_fractal(r / 2);
  popMatrix();

  stroke(0, 255, 0);    // green circles
  pushMatrix();
  translate(r / 4, 0);
  draw_fractal(r / 2);
  popMatrix();

  stroke(0);            // black circles
  pushMatrix();
  translate(-r / 4, 0);
  draw_fractal(r / 2);
  popMatrix();
}

This recursive code has the following output:

Red: Top circles
Blue: Bottom circles
Green: Right circles
Black: Left circles

With origin markers:

Conclusion

I hope this was an interesting read and a good introduction to visualization in code. Processing is good for more than just trippy fractals, it's also a tool to visualize data in cool and new ways. There are plenty of fractal snippets freely available online for Processing, but feel motivated to create your own and share them here if you come up with something cool! The strokeWeight(...), stroke(...), noFill(), fill(...), and background(...) might be interesting to tweak for adding more color. For further documentation, checkout Processing's website.

Discussion

markdown guide