For the Fractal Formulas blog, we will be using the program JWildfire for flame fractals. It is free, open source software written in Java, available at http://jwildfire.org/. We will be focusing on the concepts and formulas here, not the mechanics of how to use it. You should have JWildfire installed and running so you can follow along as we explore how it works (there are some installation instructions and basic tutorials at the JWildfire Wiki).
A flame pack containing some of the steps we will go through is at https://pastebin.com/cPLRs02Y. There are two ways to retrieve it. You can use the download button to save the flame pack to a file (remove the “.txt” from the end for JWildfire to see it) and click the Load Flame button in JWildfire to load it. Or select the text (the easiest way is to scroll down to the bottom and triple-click in the RAW Paste Data section) and copy it to the Clipboard (Ctrl-C), then in JWildfire click the From Clipboard button.
The examples here use a resolution of 500×500, but JWildfire doesn’t set that automatically from the flame pack. To change it, use the menu between the Render and Batch Renderer buttons at the top left of the window. If it doesn’t have a 500×500 selection (it won’t by default), click the “…” button to add one.
We learned in Basic Fractal Concepts that orbital fractals result from the orbit generated by iterating a formula. Flame fractals are a type of orbital fractal where the “formula” is actually a set of transformations or transforms, one of which is chosen randomly at each iteration. In this article we will examine the details of this process, often called the “Chaos Game”.
Although transforms act on individual points when computing an orbit, it is helpful to visualize how transforms map a shape to a new one by applying it to each of the points in the shape. Consider, for example, a function that simply divides the x and y coordinates by 2. Iterating this function on some point results in a sequence of points (the orbit) that get closer and closer to the origin (0,0). Applying the function to a square maps it to a smaller square that is closer to the origin (each point in the original square is divided by 2). Iterating the function on a square results in a sequence of smaller squares that get closer and closer to the origin. We’ll use this technique frequently as we explore fractal formulas in this blog.
Flame fractal transformations have three parts:
- An affine transform, which is simply one that maps parallel lines to parallel lines. It can rotate, scale, move, skew, or even reflect the input points. Angles may change, but lines remain lines and parallel lines remain parallel. So an affine transform will always map a square to a parallelogram (possibly, but not necessarily, a square or rectangle).
- A non-linear transform, defined by one or more variations that can do anything. JWildfire contains hundreds of variations, including some that let you define your own. The simplest variations are “linear” and its 3D counterpart “linear3D”, which simply scale the input points by some value (often by 1, which means they don’t change the points).
- A post-affine transform, which is like the affine transform (sometimes called the pre-affine transform), but it is applied after the non-linear transform instead of before it.
When we add a new transform, it does nothing. The affine transforms don’t change the input points, the non-linear transform is linear3D with a value 1, which doesn’t change them either. We need to change one or more of the three parts to make the transform useful.
One kind of variation is called a “shape” or “blur”. These variations define a shape by generating a random point somewhere in the shape. The input point is ignored, so the orbit of a transform that has only a shape variation is just a sequence of random points from the shape. (They are sometimes called “blurs” because adding them to a transform with other variations tends to make the result blurry. There is also a variation called “blur” which generates a circle.) When a shape variation is used by itself in a flame, we can see the unadorned shape. Here are some examples:
The top row uses the variations spirograph, nBlur, and starblur; the bottom row uses superShape3d, crackle, and dla_wf. All have a number of parameters to change how they look; the examples above show just one possibility for each shape.
Let’s start with a starblur such as the one at the top right and set its value to 0.25. We add a new variation, which doesn’t change the shape since new variations do nothing by default. On the Affine tab, we first move the new linear3D transform right and down, then rotate it 45° clockwise, and finally shrink it 10%. Here is what the image looks like after each of these steps:
Let’s go through each of these steps thinking of the transforms as maps that transform a shape. The starblur transform doesn’t map anything; it ignores the input and just generates a yellow star shape centered at the origin (shifted to near the top of these images). The first iteration of the linear3D transform maps the yellow star to a blue star that is shifted, rotated, and scaled according to the affine transform. The second iteration maps the blue star to the first purple star, and subsequent iterations map each purple star to the next one in sequence. (We’ll see why the colors work the way they do shortly.)
In the first image, the affine transform doesn’t change the shape; it maps it to itself. But the color is changed because all of the linear3D transform iterations are on top of each other. In the second image, each linear3D iteration moves the star down and to the right. Most are not visible here, but the line of stars continues forever (albeit getting fainter as they get further from the original star; we’ll come back to that).
In the third image, the first iteration rotates the yellow star 45° before it is moved, so the blue star is in the same place as before, but rotated. For the second iteration, the blue star is rotated 45° around the origin, moving it to the left and down a bit before being moved right and down to its final position as the first purple star. This is repeated for each subsequent star, arranging them in a circle. There are eight stars in the circle because 360/45 equals 8. If we had rotated by 40°, there would have been nine stars in the circle.
In the last image we add shrinking, so in addition to rotating around the origin each successive star is 10% smaller, resulting in a spiral. But flame fractal software doesn’t work with shapes as we have been doing; it doesn’t draw a star (or any other shape) and replicate it. That is just a convenient way for us humans to make sense of what the transforms do. Software works with individual points. Let’s walk through this process for the last image.
First, we need to examine the gradient. The flame algorithm computes a color value for each point which is just a number between 0 and 1; a gradient is used to convert this color value (or color index) to an actual color. The gradient for this flame (you can see it on the Gradient tab) is a simple one, with just four colors. Color values between 0.0 and 0.25 are red, values between 0.25 and 0.5 are green, between 0.5 and 0.75 are blue, and between 0.75 and 1 are purple.
We start with a random point that has a random color value, say (-0.3194,0.1124) with color 0.630. For the first iteration, we pick one of the transforms at random. Think of it as flipping a coin: heads we pick starblur and tails we pick linear. Let’s pick starblur. That transform ignores our random input point and produces a point somewhere in the yellow star. To color it, we average the current color value (0.630) with the transform’s color (0), getting 0.315, which is green.
For the second iteration, we again choose the starblur transform, and produce another point somewhere in the yellow star. It’s color is (0.315+0)/2=0.158, which is red. As we proceed, half of the points in the yellow star will be colored red and half green. These combine to produce yellow, which is how we get a yellow star even though there is no yellow in the gradient.
For the third iteration, we pick the linear transform. It takes the second point and scales, rotates, and moves it, resulting in a point in the blue star corresponding to the previous point in the yellow star. The linear transform has a color value of 1, so we average that with the current color to get (0.158+1)/2=0.579, which (no surprise) is blue.
We obviously don’t want to repeat this manually millions of times; that’s why we have computers! But let’s go one more iteration, then try to generalize. We pick the linear transform, which takes the third point (in the blue star) and maps it to a corresponding point in the first purple star, with a color value of 0.789, purple.
So every iteration when starblur is chosen, a new point in the yellow star is produced (unrelated to the previous point in the orbit). If the previous point was blue or purple, the new point will be green, otherwise it will be red. Again this combination makes the star yellow overall.
Every iteration when linear is chosen, the previous point (in some star) is mapped to the corresponding point in the next star. If the previous transform was starblur, the previous point will be red or green and the new point will be blue. Otherwise, it will be purple. This is exactly what we see.
A point gets added to the blue star whenever linear is chosen right after starblur. A point gets added to the first purple star when two linears in a row appear after a starblur. A point gets added to the second purple star when three linears appear in a row, and so on. A point gets added to the eleventh purple star when twelve linears appear in a row. That’s like flipping a coin twelve times and getting tails each time! It isn’t very likely. But it’s far from impossible; in fact, it’s almost the same probability as getting a “four of a kind” in poker. With a sequence of millions of “coin tosses”, there will be lots of runs of twelve tails in a row. But not nearly as many runs of twelve as runs of three, which is why the eleventh purple star is dimmer than the second one.
We can’t change the need for long runs of the same transform to produce points further along the spiral, but we can adjust the probability to make long runs more likely. This is done by changing the Weight values for the transforms. For example, here are the results of setting the Weight for the linear transform to 1, 2, and 3, respectively.
There is no “correct” value; it depends on the fractal and the desired effect. Here, a value of 1 defines the spiral a lot better than the default of 0.5, but 3 muddles the center; 2 seems to be the best (although values near 2 such as 1.8 or 2.1 are not shown).
The weights are relative; setting the weights for both transforms to 2 would be the same as leaving them at 0.5. But a transform with a weight of 2 is four times as likely to be chosen as one with a weight of 0.5. In our coin toss analogy, it’s like tossing a weighted coin that comes up tails more often than heads.
Notice that besides increasing the density of the spiral, increasing the weight of the linear transform has shifted the yellow star to green. The points in that star are colored red when the previously selected transform was also starblur and green when it was the linear. With equal weights, the points were colored equally red and green, making yellow. But with a higher weight on the linear, there will be more green points and fewer red points, resulting in the color shift. The gradient we are using here is admittedly contrived, but the lesson is to watch for color shifts when adjusting transform weights.
Now that we’ve examined the fairly simple case of a spiral made from an iterated shape, let’s make it a bit more complex by changing the starblur to linear3D. We’ll keep the amount at 0.25. This set the radius for the starblur; for linear it is a multiplier,so both x and y will be multiplied by 0.25. Here is the result:
The stars have been replaced by smaller copies of the fractal. Instead of ignoring the input point like starblur did, the first transform now maps the fractal to one that is a fourth the size and moved closer to the origin (which is at the top tip of the fractal here). The second transform hasn’t changed, and does the same thing as before, only now replicating the top fractal to smaller ones in a spiral instead of the star.
To understand how it works on points, pick any point that is part of the fractal and consider what each of the transforms do to it. The second transform works just as it did before: it maps the point to the corresponding place in the next area. The first transform works very differently: the x and y coordinates of the point are multiplied by 0.25. If you imagine a line between the point and the origin, the new point will be the point on that line one fourth of the way from the origin to the new point. This will always be in the top part of the fractal. If the original point was blur or purple, the new point will be green. If the old point was green or red, the new point will be red.
For example, take the lowest point at the bottom of the fractal (it’s purple) and iterate the first transform a couple of times. The first iteration will map it to the lowest green point in the fractal. The second iteration will map that to the lowest red point. The third iteration will map that to the lowest point in the small “blob” at the top of the fractal. To continue, we would need to magnify the fractal. If we magnified the top “blob” to be the same scale as the entire fractal, it would look just like the fractal (except all red).
(If you are following along in JWildfire and want to try this, go to the Camera tab and change the Zoom value from 1 to 15 and the CentreY value from 0.6 to 0.375. But in general we don’t zoom in to flame fractals. To render just the zoomed in red part still requires generating the unseen orbit points for the rest of the fractal, so it is not very efficient. They are also pretty finicky: small changes to the parameters and coloring have a larger effect on the (small) visible part of the fractal.)
It is critical the the transform used to compute each orbit point be chosen at random. Any pattern in the sequence of transforms used will cause a corresponding sequence of points in the orbit, and only part of the fractal will be generated. It is amazing when you think about it that the intricate patterns associated with flame fractals come from, indeed require, randomness.
So we see how the transforms map any point on the fractal to another point on the fractal. But what happens to points that aren’t part of the fractal? In particular, we start the process with a random point, which is probably not part the fractal (especially a fairly sparse fractal like this one). How does it lead to the fractal? Mathematically, the fractal is called an “attractor”, meaning that it will attact the orbits of points not on the fractal; each successive point in the orbit will get closer to the fractal. The first dozen or so orbit points are not part of the fractal, so the flame algorithm will ignore them, and only start to plot the points after the first few dozen.
Let’s do something about the rather boring colors. Most of the problem is the very simple test gradient we’ve been using, so let’s change it to one of the built-in gradients: rw-multi-reds-oranges.
The first picture below shows the result. It’s a lot better than the four color gradient, but most of the center is the same color–the last color in the gradient. Recall that the center of the fractal is generated by runs of using the second transform many times in a row. Every time the second transform is used, the color index moves halfway to the right side (the color associated with that transform). There are only 256 colors in a JWildfire gradient, so it gets to the last color pretty quickly.
To improve this, we need to make the color index move toward the transform color more slowly. This is done by increasing the color Speed parameter. It seems backwards to reduce the speed by increasing the Speed parameter, but that is how it works. The middle picture below has a Speed of 0.5, and the right picture has a Speed of 0.9. In general, when the weight of one transform is increased relative to the others (as is done here), increasing the Speed value helps distribute the colors more evenly.
At the extreme, when the Speed is 1, the color won’t change at all. This is more useful for fractals with more than two transforms; here the first transform pulls the color toward 0 (the left side), so setting the second transform speed to 1 will color the whole fractal with the first color in the gradient.
The Speed value can also be negative, which moves the color index towards the transform color more quickly. At the extreme of -1, the color is set immediately to the transform Color value. This is a useful trick for analyzing parameters for a fractal: set the Speed for all of the transforms to -1 and the Color of each to a different gradient color to see what parts of the fractal are generated by which transform.
Changing the affine transform for a shape variation doesn’t do anything; the point is appropriately transformed, but the shape variation ignores it. But now that we are using linear, it does have an effect. For example, the left figure below shows what happens when the first transform is rotated 90° clockwise. As we would expect, all of the spirals are rotated; the top one because of the rotation, and the rest because they just copy the first one.
More interesting fractals can be obtained by changing the linear3D to another variation. Most variations have parameters that can be changed to produce different effects. For example, changing it to escher, leaving the parameter beta at the default 0.3 results in the middle figure below, and changing beta to -0.88 results in the right figure.
We aren’t going to delve into the details of how the different variations work here; that’s the goal of future blog posts. Experiment! Try different variations to see how they work. Different gradients will emphasize different parts of the fractals. Shape variations will just repeat the shape in a spiral, just like starblur did. If you are new to flame fractals, this is one way to get a taste for what the various variations do. But be aware that the ones beginning with “pre_” or “post_” must be used in combination with other variations; they won’t work by themselves.
One last tip: Many variations are designed to work on the “sweet spot” right around the origin, but the fractal as we have constructed it here is not centered there. To compensate and make the variations work on the spiral fractal to their fullest, we need to use the affine transform to move the center to the origin. One way to do this is to change the first transform to use the variation eyefish. Then with that transform selected, click the “Move triangles” button and move the T1 triangle to center the spiral on the eyefish sweet spot. The direction will depend on the rotation of the transform. To illustrate, the first image below shows the 90° rotated transform with no movement; the spiral is on the right side of the sweet spot. If we move the T1 triangle to the right, we can center the spiral, as shown in the second image.
The effect of this on another transform that works on the “sweet spot”, julian, is shown in the last two images. In both cases, eyefish is changed to julian, with the parameter power set to 2. The one on the left leaves the transform uncentered (like the first image), and the one on the right uses the centered transform. We can’t say one is “better” than the other, only that they are different.
The emphasis of this article has been on how flame fractals work, but tweaking the basic fractals we have used here can yield interesting results. To close, here is an example using the horseshoe variation: