Primary Menu

Drawing the Mandelbrot Fractal in C#

I suppose you could say I had a deprived coding childhood; I already wrote about how I never calculated pi and now I am about to tell you that until this afternoon, I had never drawn the Mandelbrot set. I don’t know why I never took the time to do so, but as with the pi calculator, when I decided to plot the Mandelbrot set, I found a very interesting coding challenge waiting for me.

The first step in the process was to fix the notoriously slow Bitmap.SetPixel() method. I haven’t decompiled System.Drawing to look at .NET’s implementation but I assume it involves some sort of Marshal.Copy()ing of unmanaged bitmap data to a managed byte array, modifications to pixels in the managed byte array, and recopying the array to unmanaged memory. That’s well and good for setting three pixels. We’re going to render Mandelbrot sets of an arbitrary size; 2800×1600 is about 4.5 million pixels. Bitmap.SetPixel() would make this process way, way longer than necessary.

I created a class with a readable, writable bitmap as well as a method to set any of its pixels using unsafe code.

This class isn’t very useful outside of this program; it would need some modifications to use pixel formats other than 24bpp RGB. However, it gets the job done! The SetPixel method is what makes this class useful. It locks the provided Bitmap’s pixels, then gets a pointer to where the first color byte of the first pixel is in memory (Scan0.ToPointer()). It then figures out what the offset is to the pixel we want to modify. Finally, it creates a pointer to the pixel we want. It sets the blue, green and red to the specified color’s blue, green and red, then finally unlocks the bitmap data. When the data gets unlocked, it is saved in memory.

The SetPixel method presented here does not provide tremendous performance. It does, however, let you work with a bitmap fast enough that you won’t get bored. Most Mandelbrot rendering time is in calculations, anyway.

Now that we have an image class, we can get down to the math. The Mandelbrot fractal is based on the following formula:

Where C is the starting point on the complex plane and the starting value is zero.

The formula is given a starting value, C, that lies somewhere in the complex plane. If the formula (using C) does not tend to infinity, then C is part of the Mandelbrot set. If C tends to infinity, it is part of the Mandelbrot set. As a quick programmatic note, if the absolute value of Z sub N (the value of the formula after N iterations) ever becomes greater than two, the formula will tend to infinity.

Knowing that, we can start coming up with some pseudo-code:

for x on the screen:
for y on the screen:
scale (x, y) to the complex plane to figure out where we are
c = where we are on the screen
z = 0 + 0i
b = a bitmap
for i = 0 to however many iterations:
z = z^2 + c
if |z| > 2:
plot (x, y) on b as some color that indicates how much "infinite tendency" there is at C
break

If you read the Wikipedia article about rendering the Mandelbrot set, you will notice that it uses two real numbers to accomplish the same thing as one complex one. C# has a complex number class, which we will use in our code. However, before we talk about the actual rendering, we need a color palette. The members of the Mandelbrot set will be rendered black (or actually, based on the flow of the pseudo-code, not rendered at all), while the rest of the set will be rendered some color based on how many iterations it takes for the absolute value of Z to eclipse two. The more iterations it takes, the whiter the pixel. The fewer iterations, the bluer the pixel. It all comes together in the following (very simple) method:

This method could be significantly improved on multi-core machines by dividing up the x-values to render and running a thread on each core. However, any rendering would have to be done after all the threads finished to avoid any cross-thread bit-locking issues. Luckily, the part that takes a while is the iterating, not the rendering.

That’s all it takes to draw a pretty good-looking Mandelbrot fractal. Here’s a fairly large one that you can give to your math teacher. I promise it will make him or her proud. I’m totally giving one to my math team coach as a New Year’s present.