the Site of a Developer


I saw buddhabrots around the web and I decided I just had to render some. For nebulabrots ‐ most people seemed to be making greyscale versions of different iteration depths and then combining them with a graphics package, I found it more fun to do it all in&hypen;app (produce the deepest iteration depth and paint colours as you go) and implement a few colouring methods I hadn't seen anyone else mention (like colouring based on orbit iteration count per‐pixel with various functions). I used C++ for the base application and GLFW + OpenGL for live display and colour channel adjustments.

This project is available on GitHub.


Here is a nice example of a nebulabrot. Notice that I preserved the asymmetry, if I was letting it produce enough orbits to render smooth buddhabrots then I would only begin orbits in one half while mirroring painting because the end result should be symmetric anyway.


With a square "aperture" for orbit starting regions on the complex plane (a square that moves around depending on the conditions of a basic genetic algorithm) it's possible to do loads of orbits per aperture and paint at shallow depths to get something like this. It might be fun to use a texture over the aperture to seed orbit colours.

Render Progress Animation

Here is a gif that I produced in‐app which shows the progress of a nebulabrot being rendered. Each frame shows the status of the brot between an arbitrary (because of the way I implemented it based on keypress detection) number aperture batches. You can notice that the "signal to noise" of orbits hitting the same pixels many times causes rarely hit pixels (the scattered pixels at the start) to become near‐black ‐ or completely black due to floating point accuracy when producing an image. Detail appearing in sudden bursts is the genetic algorithm at work (sticking to an aperture near the edge of the mandelbrot set on the complex plane).

Imaginary Plane Buddhagram

Here's a look at the imaginary plane (Zi Ci) with Z initialised as r = sin(Cr), i = sin(Ci).

50x Magnification

The left image is a 50x magnification of the first minibrot above the main brot in the top image on this page; a tiny green smudge (note that it's coloured differently and not rotated 90 degrees). The right image is the area on the complex plane where orbits started that passed through the magnified region, more intense = more pixels painted in the magnified region from orbits that began there. I used the metropolis hastings technique for this and also restricted the region on the complex plane where orbits could start, rather than wasting time on the entire complex plane where most orbits do not pass through the viewport. Runtime was around 20 minutes, single threaded (with many orbits calculated but not too many painted this is a good candidate for multithreading).

Same region and magnification as above but 20000 iteration orbit depths and 2 hours runtime. I also tried a hack whereby any orbits of 10000 or more were far more likely to keep mutating nearby orbits, so there are some very bright spots. Mirroring the painting would have worked very well.

80000 iterations and 3 hours this time, plus mirroring the painting. I think the mirroring looks inorganic but it does half the fuzziness.

5000x Magnification

Here is the next minibrot to the left in the 50x images above (¼ across the image), but rendered in 2048x2048 at 5000x magnification (click for full res).

Here are the orbit start intensities for an unmagnified render, as expected it shows the mandelbrot set as the longer orbits are brighter nearer the boundary.

This is an early attempt of a buddhabrot with some mistakes. More ordinary mandelbrot set shapes can be seen vividly. You can also see artifacts of how the buddhabrot rendering method works.