Cancel
Comment on ... ( toy ) ...

michaelerule Tue, Aug 19, 2008
fractal rendering

The fractals are Julia sets from the family z^2 + c. The image is rendered in a NxN (512x512 in this case) array, which represents the region of the complex plane between -2(1+i) and 2(1+i). To create this type of smooth fractal rendering, we use an iterated conformal mapping approach. To render most iterated complex function fractals, one would iterate over all points, apply a function repeatedly, and count how long it takes for the function value to escape a chosen region. Iterated conformal mapping does not speed up the rate of convergence, but does allow us to render one frame per function iteration rather than having to wait to iterate all the points, creating a faster and more responsive animation. I'm not sure how to conceptually explain this approach, so I will sketch it out in pseudo-code :

compute a lookup table Z representing the conformal mapping ( it is not absolutely necessary to do this but I found it sped up the animation )

for each point (x,y) in a NxN array
__ compute the complex number for that location : z = ((x-N/2.)+i(y-N/2.))*4/N.
__ compute z^2 : zz = z*z (complex, not scalar multiplication )
__ convert back to the grid coordinates : Z(x,y) = (real(zz)*N/4+N/2,imag(zz)*N/4+N/2)

We now have a NxN array of points which represent the function z^2 as a mapping from a NxN region to itself.

To render the fractal, create another NxN array which will represent the actual fractal image. I used a byte array. Initialize it to 0 everywhere. You need to double buffer the rendering because you end up both reading and writing from this array, so call the arrays Iter and Iternext. The routine for generating the fractal is approximately :

for ever
__ for each (x,y) in NxN
____ let z = Z(x,y) + C //get the mapping from the lookup table, add a constant shift
____ if z is in bounds
______ Iternext(x,y) = Iter(z) + 1
____ else
______ Iternext(x,y) = 0
____ output Iternext(x,y) to screen
__ swap Iter and Iternext

coloring

The loop above generates values in [0,255] which represent how many iterations of the mapping is needed before a point escapes out of bounds. To create an image, I use a lookup table with 256 color entries, of your choosing. In this case I chose a greyscale.

motion blur

You can add a motion blur effect. You want to store the screen image in a separate buffer ( in Java I used a BufferedImage ). This gives you direct and consistent access to the pixel data. To do a motion blur, when you update pixel (x,y) to color c, do a weighted average with the current pixel value rather than just overwriting. If your working with Java's integer packed RGB colors 0xRRGGBB then the following little function does a quick weighted average, where the weight are integers and sum to 256 rather than 1.

/** average two colors based on two given weights */
public static int average(int c1, int w1, int c2, int w2) {
return 0x00FF00FF & (((c1 & 0x00FF00FF) * w1 + (c2 & 0x00FF00FF) * w2 + 0x00800080) >> 8) |
0x0000FF00 & (((c1 & 0x0000FF00) * w1 + (c2 & 0x0000FF00) * w2 + 0x00008000) >> 8);
}

mouse input

A whole range of fractals can be rendered by adding a variable offset onto the existing mapping. For this toy, this offset C is taken from mouse input. The center of the field is taken to be 0, and the offset is just the mouse displacement in pixels from the center. To make the animation smooth, damp the mouse motion by keeping a separate (x,y) point variable and have this point exponentially decay toward the real mouse position. For instance, if Mx is your mouse x position and Cx is the x component of the offset, then on each iteration you would do
Cx += a * ( Mx - Cx ) where a determines the tracking rate and is between 0 and 1 (I use a=.1)