Wrapping Images around Fractals

I remember back in 2015 when I watched a video about the Mandelbrot Set and how it works. I was completely mind blown and started immediately to code it and experiment with it. I guess the video explains the mechanism of making Mandelbrot and Julia Sets very clearly; so I won't be explaining it here.

Let's say we have a bailout value at which we stop the iterations for each pixel to decide what color should the pixel be. The classic way to choose the color is to choose it according to the number of iterations it took to reach the bailout value. In this article we will be interested in the complex number we obtain from the last iteration. Let's try to visualize that last complex number. Since the magnitude of the complex number after the last iteration will mostly be greater than the bailout value, it will be tricky to choose a color according to it. So, instead of using the magnitude let's focus on the angle for now.

Here is a Julia Set where the angle of the last complex number -- between 0 and 2Pi -- is bound between 0 and 1 to grayscale colors between black and white.

As we can clearly see, "layers of bricks" emerge from this visualization, and we already have the x coordinates to place textures on these bricks, how cool is that! Now, if we look closely, we can see that each layer corresponds to an iteration. This means that if we manage to find a way to bind each layer to values from 0 to 1 tranversally, we get the exact y texel coordinates to place the textures on the bricks. Let's try using the magnitude.

After a lot of debugging, I realised that the magnitude is very close to the bailout value at the innermost pixels of each layer and very close to the bailout value squared at the outermost pixels. So, let's try to map the bailout value to 0 and its square to 1. Here is what we get :

$bailout < magnitude < bailout^2$
$0 < magnitude - bailout < bailout^2 - bailout$
$0 < \frac{magnitude - bailout}{bailout^2 - bailout} < 1$

Notice something wrong? Yes, it's too dark : the value we're visualizing is growing "slowly" from 0 to 1. Actually, it's growing exponentially! Let's try to log everything to make it linear!

$log(bailout) < log(magnitude) < log(bailout^2)$
$0 < log(magnitude) - log(bailout) < log(bailout^2) - log(bailout)$
$0 < \frac{log(magnitude) - log(bailout)}{log(bailout^2) - log(bailout)} < 1$
$0 < \frac{log(magnitude/bailout)}{log(bailout)} < 1$

Ah! There you go! Now we can use the x and y texel coodinates that we calculated previously to place textures in this Julia Set.

Ok, this seems to be working fine, but the result does not look quite appealing, with all my respect to Lena. Maybe we should choose another image? But on which criteria should we base our choise? To answer this question, let's take a closer look at the sizes and positions of the bricks. If we unfold some of the layers of bricks, this is what we get :

The following figure shows a very important property of the bricks : each layer is two times bigger than the layer bellow it. Now, what we are looking for here is an image that matches with what's around it when used as a texture for each brick. In other words, we're looking for some properties to verify for the texture in order for it to look better.

One property that easily comes to mind when we see the layout of the bricks above, is to make the left and right borders of the image match. This means that there must be a continuous pattern on both sides.
Note : most modern banknotes have this property.

Another property than is essential for this to work, is that the entire top border matches with half of the bottom border as indicated in yellow in the figure.

Last but not least, what's remaining of the image's borders are two parts : the bottom left quarter and the bottom right quarter indicated in red and green in the figure. The bottom left quarter must match with the top right half and the bottom right quarter must match with the top left half.

## Some results

Notice how there is too much detail at the center of the fractal? This is due to the small size of bricks at deeper layers causing undersampling of the texture. To make this fractal look better, let's try to hide those deeper layers by shading them away. Here I multiply the color values of each pixel by $exp(-\frac{iteration-a}{b})$ for all pixels where iteration is higher than a. In this formula, iteration is the number of iterations it took to eventualy reach the bailout value, a and b are values used for tuning the shading and are set respectively to 7 and 10 for the image below.

The fractals in this article are made using some C code I wrote in 2015 that is so experimental and poorly written that I am kinda ashamed to show it. Maybe one day I will revisit this project and properly rewrite the whole thing.