Visit the new site

Fast Mandelbrot Renderer

Published on 13 November 2008

Here is another version of the classic Mandelbrot set, however this one runs fast enough in Pixel Bender for real-time zooming all the way down to the limit of the floating point number precision (at which point you get some glitchy goodness).

Adobe recently launched the Pixel Bender Toolkit, which is a high-performance graphics processing language for image processing. It will offload the image processing to the GPU enabling very high performance operations. 

You will need to install the Pixel Bender Toolkit (available as a free download here) and then copy & paste in the code below.

Some pixel bender scripts can be compiled into filters than can be used within Flash 10 applications. However, Flash doesn't yet support filters with loops like this one, so we won't have a super-charged Flash fractal explorer just yet.

/**
* Mandelbrot.pbk
*
* Copyright (c) 2008 Tom Beddard
* http://www.subblue.com
*
* Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*
*
* Tips:
* - Use the centerPreset option to jump to interesting parts of the Mandelbrot set.
* - Increase the maxIterations option to increase detail on high zooms.
*
* As loops aren't supported with Hydra code it curently isn't possible to export this
* for use in Flash.
*/

<languageVersion: 1.0;>

kernel Mandelbrot
< namespace : "com.subblue.filters";
vendor : "Tom Beddard";
version : 1;
description : "Mandelbrot set renderer";
>

#define BAILOUT 10.0

{
output pixel4 dst;

parameter int2 size
<
minValue:int2(100, 100);
maxValue:int2(1000, 1000);
defaultValue:int2(640, 480);
>;

parameter float2 center
<
minValue:float2(-2.0, -1.0);
maxValue:float2(2.0, 1.0);
defaultValue:float2(-0.5, 0.0);
>;

parameter float2 centerOffset
<
minValue:float2(-1.0, -1.0);
maxValue:float2(1.0, 1.0);
defaultValue:float2(0.0, 0.0);
>;

parameter int centerPreset
<
minValue:0;
maxValue:4;
defaultValue:0;
>;

parameter float zoomMajor
<
minValue:0.0;
maxValue:20.0;
defaultValue:0.0;
>;

parameter float zoomMinor
<
minValue:0.0;
maxValue:10.0;
defaultValue:0.0;
>;

parameter int maxIterations
<
minValue:20;
maxValue:800;
defaultValue:200;
>;

region generated()
{
return region(float4(0, 0, size.x, size.y));
}

void
evaluatePixel()
{
pixel4 p;
float aa, bb, zz, twoab;
float x0 = center.x;
float y0 = center.y;

// Use a center preset to find some nice parts of the Mandelbrot set
if (centerPreset == 1) {
x0 = -0.742522478103764;
y0 = -0.143708014488453;
} else if (centerPreset == 2) {
x0 = 0.36295341867850555;
y0 = -0.6455617463848476;
} else if (centerPreset == 3) {
x0 = 0.3218759918211005;
y0 = 0.03518083572368085;
} else if (centerPreset == 4) {
x0 = -1.673497088962531;
y0 = -0.0003318667941149705;
}

float zoom = exp(zoomMajor + zoomMinor);
float x1 = x0 - 2.0 / zoom; // Left limit of x
float x2 = x0 + 2.0 / zoom; // Right limit of x

float spanX = x2 - x1;
float spanY = spanX * (float(size.y) / float(size.x));
float y1 = y0 - spanY / 2.0;
float y2 = y0 + spanY / 2.0;

x1 += centerOffset.x * spanX; // Shift centre for fine tuning of position
y1 += centerOffset.y * spanY;

float2 z = float2(x1, y1) + outCoord() * float2(spanX / float(size.x), spanY / float(size.y));
float2 z0 = z;
int n = 0;

dst = pixel4(0.0, 0.0, 0.0, 1.0); // Set everything to black first

/**
* Mandelbrot formula
* z' = z^2 + c
* where: z = a + bi
* z^2 = (a^2 - b^2) + (2ab)i
* and: c = x + yi
*/
while (n < maxIterations) {
aa = z.x * z.x;
bb = z.y * z.y;

if (aa + bb > BAILOUT) {
// Fill the pixel based on the time it takes to reach the bailout threshold
p = pixel4(1.0 - float(n) / float(maxIterations));
p.a = 1.0;
dst = p;
break;
}

twoab = 2.0 * z.x * z.y;
z.x = aa - bb + z0.x;
z.y = twoab + z0.y;
n += 1;
}
}
}

  Last updated: 14 November 2008

10 Comments

  • Kevin Goldsmith commented at 14 November 2008 at 17:56

    sweet!

    You forgot to paste in the language version in your code:
    need to have

    <languageVersion: 1.0;>

    at the top

  • Tom commented at 14 November 2008 at 19:25

    Cheers Kevin :)

  • dragonfly commented at 15 February 2009 at 11:04

    Great visualizations of the Mandelbrot set!

    I also played with fractals in Pixel Bender -- it's really awesome! The speed is fascinating! And the code is pretty simple and straightforward.
    You can see my version of Pixel Bender fractal renderer at http://octets.ru/programmirovanie/flash-texnologii/pixel-bender-bystraya-otrisovka-mnozhestv-mandelbrota-i-zhyulia/
    I tried to make fractal coloring "non-conventional" ;)

  • Symbol commented at 7 March 2009 at 10:41

    Btw, do you know some good AS3 tutorial site? I'm normal with AS2 but practically don't get a thing in this new actionscript.. :(

  • Tom commented at 7 March 2009 at 22:43

    Symbol, I would highly recommend Colin Moock's book Essential Actionscript 3.0 from O'Reilly. After that Google is your friend ;-)

  • Satya Meka commented at 11 July 2009 at 08:17

    I actually learned a lot about Pixel Bender from your Fractal Code, than the official Pixel Bender Documentation! Great Work Tom!

  • Joacim commented at 10 November 2009 at 17:00

    Strangely, this filter makes my screen flicker, and then my computer crashes. Maybe it's a snow leopard related bug. Have anyone else experienced something similar on osx 10.6?

  • Tom commented at 10 November 2009 at 19:26

    Joacim: I've also had similar issues with the FractalExplorer filter since upgrading to Snow Leopard on my iMac. It seems to be due to the looping in the filter.
    I haven't investigated it much as it's not nice when the whole system locks up, but I'll post a message in the PixelBender forums to see if other people are experiencing problems too.

  • Tom commented at 11 November 2009 at 08:55

    Update: the recent 10.6.2 update of Snow Leopard seems to have fixed some of the GPU lock-ups I was having.

  • Joacim commented at 11 November 2009 at 10:00

    10.6.2 did the trick. They seem to have fixed a bunch of other annoying stuff as well. Finally! :)

    Awesome filter by the way!