![]() |
Matt Fairclough and I attended a lecture at SIGGRAPH 2001, by a great guy, Jos Stam. He was presenting a paper explaining a technique for rapidly simulating
a fluid. The demonstrations were stunning. He showed very fast, smooth fluids in 2D, and even some 3D fluids, running at a reasonable speed.
But he waited till the end before proudly showing us a fluid simulation running at full speed on his palm top. Most of the simulations showed Smoke moving around in Air. The smoke tended to be heavier than the air, and would sink to the bottom of the space, swirling beautifully. The thicker the smoke, the faster it would sink. So we got thinking. Surely this would be a perfect way to simulate fire, because fire is a fluid. |
Fuel + Oxygen --> Heat + Waste
Heat: Initially, we can set the heat to zero everywhere. No combustion has taken place, and so it's cold.
|
Oxygen: Here's blue will be used to show where there is oxygen.
|
Fuel: To begin with, I'll place a small blob of yellow fuel. For simplicity, we can consider the fuel to be a gas, and so
is affected by convection. If we re-render the fuel into the array every frame, we can simulate a solid piece of evaporating fuel.
|
procedure burn
for every pixel i
{
O = oxygen[i];
F = fuel[i];
H = heat[i];
reaction_rate = (O*F*H - energy_barrier) * rate_constant
if (reaction_rate < 0) reaction_rate = 0 Limit the reaction rate so
if (reaction_rate > maxrate) reaction_rate = maxrate it doesn't blow up (literally)
oxygen[i] -= reaction_rate Use up the reactants
fuel[i] -= reaction_rate
temp[i] += reaction_rate * Exothermicness And increase the temperature
if (oxygen[i] < 0) oxygen[i] = 0
if (fuel[i] < 0) fuel[i] = 0
}
end of procedure
|
You can see that there are several constants here, energy_barrier, rate_constant, maxrate, Exothermicness, which control various aspects of the reaction. Since this is not a real accurate simulation, we can just find the right values for these by trial and error.
Heat: A small amount of heat generated in the reaction.
|
Oxygen: Oxygen around the fuel used up.
|
Fuel: No fuel left.
|
procedure setForces
for every pixel i
{
velocity_vert[i] += temp[i] * Convectivness Cause convection (up is positive)
velocity_vert[i] *= velocity_damping Add a little damping for stability
velocity_horiz[i] *= velocity_damping
}
end of procedure
|
The sudden heating caused by the combustion of the fuel, will therefore make the gas expand. This is a good thing to include in your simulation, but is not essential.pressure = temperature volume
The Palette
Fire gives off light for two reasons. Firstly the high temperature of the gasses causes them to glow, in the same way that a hot piece of metal glows. The hotter the
gas, the more energy is given off. Slightly hot gas gives off mostly long wavelength (low energy) light (infra red). As the temperature increases, it begins to give off
light of shorter and shorter wavelengths; first red, then red and green (yellow), then blue as well, making it appear white.
The other reason fire gives off light, is as part of the chemical reaction. If you look at a candle flame, you can see a little blue light given off at the very base. For the time being, I shall ignore this, as it is hardly seen in larger flames.
The power of light of a particular wavelength (&lambda), given off at a particular temperature (t) is given by the Planck Energy Distribution Equation, also known as the Black Body Radiation Equation:
Since the calculation of the colour of light for a temperature involves that hideous computation, it would be a good idea to pre-calculate a spectrum of colours for the range of temperatures you'll be using.
constants
h = 6.626 x 10-34
c = 3.000 x 108
k = 1.380 x 10-23
red_wave = 0.70 x 10-6 wavelengths of red, green and blue light
grn_wave = 0.56 x 10-6
blu_wave = 0.47 x 10-6
exposure_level = 50.0 Camera exposure level (see exposure function)
procedure lightpower(wavelength, temperature)
L = wavelength
T = temperature
power = L5 * e((h*c)/(k*T*L))-1)
power = 10-28 / power I haven't bothered with the correct numerator,
I just chose something to give values roughly < 1.0  
return e
end of procedure
procedure InitColours
loop i from 0 to NumColours-1
T = remap i from the range (0..NumColours) to (MinTemp..MaxTemp)
RED[i] = expose(lightpower(red_wave, T), exposure_level)
GRN[i] = expose(lightpower(grn_wave, T), exposure_level)
BLU[i] = expose(lightpower(blu_wave, T), exposure_level)
GRN[i] = expose(lightpower(grn_wave, T), exposure_level)
BLU[i] = expose(lightpower(blu_wave, T), exposure_level)
powerloss[t] = pow(t/MaxTemp, 4.0)*10;
end of loop
end of procedure
|
Find out more information about the exposure function.
And after all that, your spectrum should look something like this:

Smoke
If there is insufficient oxygen, and if you assume your fuel is carbon-based, then any unburned fuel should become smoke.
Rate Of Cooling = R * T4
Where R is some constant which can be fiddled with. The important thing is that the cooling follows the fourth power law.
procedure initialise
initialise colours
initialise fluid dynamics
initialise fuel array
initialise oxygen array
initialise heat array
end procedure
procedure Main Loop
burn reactants
calculate convection forces
calculate fluid dynamics
replenish fuel and oxygen
cool
render
end procedure
|
There are a lot of controls to play with:
| Oxygen: | The concentration of Oxygen in the atmosphere. |
| Fuel: | The concentration of Fuel in the pile below. |
| Combustability: | The reaction rate multiplier. Greater values mean the fuel burns quicker. |
| max burn rate: | An upper limit on the burn rate seems to stop things going out of control. |
| Energy Hill: | The amount of energy needed before a reaction will start. |
| Temp2Light_Mul: | (for rendering) Adjusts the conversion from heat to light. |
| Temp2Light_Add: | |
| Exothermicness: | The amount of heat generated in the reaction. |
| Velocity Damping: | Kinetic energy removed from the movement of the air helps to keep it stable. |
| Initial Fuel Warming: | The energy provided to ignite the reaction. This stays on after ignition. Lower the value, and see it smolder. |
| Up Draught: | Gently blowing from below to fan the flames. |
| dt: | Simulation time step. |
| powerloss_adj: | Rate at which the flame looses energy through radiation. |
| Convectiveness: | The buoyancy of the hot gas. |
| Fuel Width: | Lets you adjust the spacing of the fuel blocks. |
| Fuel Height: |

References
Papers by Jos Stam: http://www.dgp.toronto.edu/people/stam/reality/Research/pub.html
Links to some great papers such as: A Simple Fluid Solver based on the FFT, and Stable Fluids.
Wispy smoke using a FFT fluid dynamics solver, Gustav Taxén:
http://www.nada.kth.se/~gustavt/fluids/
I used Gustav's public domain source code which he bravely wrote using Jos Stam's example code. I tried this myself, but gave up, frustrated
by the FFT. Many thanks to Gustav for making his code public.
Computer Simulations In Physics:
http://panoramix.ift.uni.wroc.pl/~maq/
A brilliant site, with lots of physics simulation examples, including Computational Fluid Dynamics.
Ron Fedkiw's Homepage:
http://graphics.stanford.edu/~fedkiw/
Ron Fedkiw is another of the inspiring speakers I saw at SIGGRAPH. He has written many papers on fluids, and other simulations. But the
real attractions here are the most beautiful animations of liquids, flames and cloths.
|
|