The first inspirations from this project came from an interest in the Mandelbrot set. I saw all these really fascinating looking renders and wondered how people made them and why it looks the way it does. You can see a few examples of spots in the set:
The Mandelbrot set isn't a graphed equation like you might normally see. Instead, it's a recursive function visualized on the complex plane. That might sound super intimidating, but its actually way simpler than you might think. The first part of understanding how it works is understanding what recursions are. Essentially, its an equation where a number or term is repeatedly passed through.
The Mandelbrot set isn't a graphed equation like you might normally see. Instead, it's a recursive function visualized on the complex plane. If you aren't familiar with those terms, that sounds super intimidating, but its actually way simpler than you might think. The first part of understanding how it works is understanding what recursions are. Essentially, its an equation where a number or term is repeatedly passed through.
In this example, we see a recursive function where it takes the last term and adds a constant "d" to it. For example if we started with 4 and d was equal to 2, the sequence would go: 4, 6, 8, 10, 12, and so on.
This recursive function acts the same way, with passing the terms through. In this case, the previous term is expressed as Zn instead of Zn-1 but since our term is equal to Zn+1, its the same thing. For this function, an example of how the sequence would with -2 as the start term and c = 2 would be: -2, 6, -6, 18, -30, and so on
With the Mandelbrot set, the recursive function is exactly the same as the second one I just showed: Zn^2 + C. Rather than using just a single component term like integers, it uses a two component binomial on the complex plane. Despite its name, the complex plane can be pretty simple. All it is is a way of expressing cartesian coordinates (x,y) with a summed binomial (a + bi). Lets visualize it!
Here, we can see a simple application of the complex plane. Its showing us a point (3+4i) on the plane. The i term is referring to the imaginary number, √-1. The imaginary component is what can make this, well, "complex". Since the square root of negative one doesn't exist, it's hard to understand, but all we need to know for this application is that this plane makes it possible to use recursions for a 2d point.
Here, we can see the recursive function for the Mandelbrot set, Zn^2 + C plotted on the complex plane. All it's doing is sampling each pixel, checking the corresponding binomial, passing it through the function, and checking to see if the outputted number ever reaches above 2. The reason it's specifically two, is because anything above 2 would mean that the number would eventually reach positive or negative infinity if passed through the function forever. If it never goes above 2, its considered "in the set", and is colored black. Sometimes the color of the pixel is determined by the value of its last iteration as well, or how many iterations it takes to go above 2.
When integrating this algorithm into any coding language, you have to make a few adjusments to how its calculated. Since computers operate on binary math, and generally don't like using imaginary numbers, you have to adjust the equation so that it can run. You have to square the coordinates of each pixel so that the imaginary component is removed (root -1 squared is just -1). This makes it super easy to calculate. And then, since the coordinates are squared, the escape value of two is squared to four.
(a + bi)² //Squaring the complex number
= a² + 2ab - b²
= (a² - b²) + (2ab)i
Here is an example of what the code for rendering the mandelbrot set per pixel would look like (written in netlogo, which has some odd syntax, but you get the point):
patches-own[explode x y return-value iteration loop-iteration]
to setup
if zoom = 0[
set zoom 1
]
ask patches [
set pcolor black
]
ask patches[
set loop-iteration 0
repeat 256[
ask patches with [pxcor = loop-iteration][
set return-value 1
set iteration 0
set y (pycor * resolution * (1 / zoom) + (y-offset * resolution))
set x (pxcor * resolution * (1 / zoom) + (x-offset * resolution))
repeat 80[
set iteration iteration + 1
let a x ^ 2 - y ^ 2
let b 2 * x * y
set x a + (pxcor * resolution * (1 / zoom) + (x-offset * resolution))
set y b + (pycor * resolution * (1 / zoom) + (y-offset * resolution))
if x ^ 2 + y ^ 2 > 4 [
set explode true
set return-value sqrt(abs(x ^ 2 + y ^ 2))
]
if return-value > 1000000000000 [
set pcolor (iteration + 1 - log log abs(return-value) e e) / log 2 e ;logarithmic coloring
stop
]
]
stop
]
set loop-iteration loop-iteration + 1
]
]
end
to default
set x-offset 0
set y-offset 0
set zoom 1
set resolution 2 / max-pycor
end
to go
end
This algorithm can produce some really stunning images, especially when zooming in pretty far :)