This simple application uses cellular automata to produce realistic looking fire. It will generate fire of any strength, length and randomness, and can imitate wind. You can customize the "burning region" using image masks or text. The fire color can also be changed easily. Large scale, the effect is too slow to be rendered on-the-fly. However, you can export to a quicktime movie and play back the animation at full speed.
OS X, or OS 8.6+ with Carbon Lib. Actually runs much faster in classic than in OS X.
A reasonably fast processor. G4 is best. I've got a 550 MHz iBook, and it's sorta slow.
What Is Cellular Automata?
Cellular Automata can be very simple or very complicated. In this example, every pixel in an image is blended with the pixels next to using simple averaging. Cellular automata can be used for everything from weather prediction to diffusion modeling. However, one application rises above the rest. The Game of Life, developed by Dr. John Conway, is perhaps the most famous math game ever invented. The game is governed by set of complicated rules, based on which cells are near other cells. For instance, a dead cell near three live cells becomes a live cell. For more information on The Game of Life, see the Wonders of Math - Game of Life.
The animation below shows small-scale cellular automata like I am using to generate the fire effect. In the second frame, a bright red dot appears in the center bottom block. This will represent heat. Perhaps it was caused by an explosion or the light of a match. In the third frame, the blocks immediately surrounding the red one become orange. They are taking mean value of the blocks around them. For example, the red block is a 10, the greatest (hottest) value possible. The white blocks have a value of 0. The orange blocks look at the red and white surrounding them and become orange, a 5 for example. In the final project, there is some randomization in this process. The rest of the animation follows the same basic principles. The explosion heat disappears in the fourth step, leaving the rest of the energy to dissipate through the blocks. Because the grid is constantly cooling, a small amount (1) is removed from the values at each step. Without this removal, the entire board would become 2/5 the value of the starting red block. (10+0+0+0+0... divided over 25 squares). With no energy removed, the end amount would be the same as the starting amount.
For more information on Cellular Automata, visit the Digital Worlds Tutorial. The code below (written in RealBasic 5) generates a simple fire effect. This code is very similar to the stuff in the application, but doesn't deal with wind, fire strength or length. In this example, the pixels are moved upwards.
for y = 1 to cs.height-1 for x = cs.width-5 downTo 5 speed = rnd + 1
leftcell = cs.cells(x - 1, y + speed).value rightcell = cs.cells(x + 1, y + speed).value centercell = cs.cells(x, y + speed).value
cs.cells(x,y).value = max(0, (leftcelll + centercell + rightcell) * firelength) next next
This section loops through the two dimensional array of cells. Each cell holds a value, which represents the "heat" at that location. These cells will later be drawn on the screen by attaching a color to each value. For each cell, the loop looks at the cells that surround it. The value of the cell is averaged with the values of those around it. The black cells around the edges of the image lower the values of the ones next to them, and so on and so forth. The result is a blended arrary of cells. Please note that the firelength variable is a number between 0 and 1/3.
for y = 1 to cs.height-1 for x = cs.width-1 downTo 1 if sourceMask.graphics.pixel(x, y) = rgb(0, 0, 0) then leftcell = cs.cells(x - 1, y).value rightcell = cs.cells(x + 1, y).value topcell = cs.cells(x, y + 1).value bottomcell = cs.cells(x, y + 1).value
newValue = max(0, min(newValue, 100)) cs.cells(x, y).value = newValue end if next next
This loop seeds the fire. The sourceMask determines which cells are seeded with random values. You can create your own sourceMask, or let the application do it for you. The mask is a black and white picture, where only the black pixels are seeded. The rest of this loop is almost the same as the one above. A newValue is calculated for the cell based on the ones around it and quite a bit of randomization. The newValue is checked to make sure it is positive, and within the range of the colors.
Okay. let's take a look at the fire application itself. Click the download link at the top of the page to get started. Wait for the download to finish and launch the Cellular Automata application. The program only has one window, which appears when it starts. From this window, you can control and export the fire effect. The picture below shows the defaults:
Here's how it works: the left side of the window allows you to customize the fire, and the right side deals with mapping and exporting. The display is located in the top-left corner and shows you exactly what the fire looks like. Within the display, the top row of pixels shows the flame gradient, the colors that it is using to render the fire. The left and right sides of the image are the wind strengths. These control how hard the wind pushes the fire.You can also see the display from the dock. (See image at right).
The strength, length and randomness values are probably the most confusing in this setup. The strength property controls the heat of the fire. Increasing the strength will increase the average heat of pixels in the seed area. The length property controls how quickly the heat dissipates as the cells rise. It must be less than 1/3. Finally, the randomness controls the consistency of the seed area. At peak randomness, the pixels will be generated almost completely at random. Lower values will result in a much more consistent effect.
The wind is actually very cool. Turn on wind, and the fire "cells" are pushed to the left. Check the "Changing" box, and the renderer will use cellular automata to vary the strength and direction of the fire. The bars in the far left and right of the display show the wind strengths. Brighter pixels push harder.
Depending on the speed of your computer, you may want to change the dimensions of the display. This can also be very useful if you are trying to generate fire of a specific size. Change the values, and press the reload button to reset the display.
The fire application has a few built in color settings. You can switch between natural fire coloring and chemical fires, and change the background from white to black. However, you can easily create your own color schemes by adding a line or two of code. Open the Globals module and look in the "createColorSchemes" method. For each scheme, the code sets up key colors. The key colors define points in the gradient. The application blends between these points to produce the entire range of colors. If you have ever used photoshop gradients you already know how this works. To create another gradient, just add the following code:
s = new CA_ColorScheme s.colors.append rgb(0,0,0) s.colors.append rgb(255,225,0) s.colors.append rgb(239,0,0) s.name = "Natural - Black" ColorSchemes.append s
Replace the rgb values with the colors you want. RGB means red-green-blue. The three values you provide (max = 255) determine what colors are used. Many graphics applications will tell you the rgb values, and you can just copy them from there. You can add more key colors by repeating the command "s.colors.append rgb(0,0,0)" with the colors you want.
The mapping section may seem the most confusing. This section controls which cells of the image are seeded with the fire. In "None" mode, the bottom two rows are used, so the fire simply goes from the ground up. In "Text" mode, the fire application generates a mask, which determines where to seed the fire. It draws the text onto the mask and the fire is produced from there. In "Use Pictures" mode, you provide your own masks. The seed mask is a black and white picture, where the black pixels are seeded areas. The other image is just for the looks. If you want, for instance, to light a farmhouse on fire, you would put the actual image of the farmhouse here. You can specify wether the image appears in front of or behind the fire using the radio-buttons at the bottom of the box. To temporarily hide the foreground image, hold down the option key. This is very useful to determine if you are seeding correctly. The picture below shows the text, none and picture modes.
The last section is relatively simple. Check the "Save as Movie" box, provide an FPS (frames per second) and export dimensions. The dimensions of the movie do not have to be the same as those you are using in the display. If you want to scale the movie on export, make the dimensions larger! Select a location to save the movie and press the • button to begin recording. Press it again to stop. The restart button "<|" erases the movie so you can start over from scratch. Note: You may have to quit the fire application before you can view the movie you create. I have been having some trouble forcing RealBasic to save the movie after you finish recording. If quicktime says the movie is "an invalid movie format", quit the fire app and then open the movie.
Well! I think that's just about it. If you have any questions about cellular automata or the fire application, drop me an email and I'd be happy to help. I know my code is badly commented, but hey! that's why it's called code. :-)
Frequently Asked Question: Why is it so freakin' slow? When I started writing the cellular automata code used in the fire application, I had no idea how much I would end up doing. The color scheming could be sped up quite a bit (when the CA_Display asks for a color, the CA_ColorScheme creates it from scratch. I should just cache them in an array), and if I thought it out, I could probably get by with fewer off screen buffers. Oh well. version 2.
1.0 = The current version. Does everything I need it too. If I end up getting a lot of requests for improvements, I will probably make another version.