Fluid Fire _________________________________________________________________ Fire Demo 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. _________________________________________________________________ How does a fire work? Very generally, fire consists of the following things: FUEL, HEAT, OXYGEN and INERT GAS. If the fuel is hot enough, and if there is sufficient oxygen, the fuel will react with the oxygen, using them up, and creating heat: Fuel + Oxygen --> Heat + Waste Three arrays to store Heat, Oxygen and Fuel Most fluid smoke simulations simulate the movement of one thing (smoke) through the fluid, and this is what they render. For the fire, we will need to transport the Fuel, Oxygen and Heat through the air. So for those, we need separate arrays, each of which behave a little differently. These arrays would not be rendered, but I'll draw them to aid explanation. [fire_h1.jpg] Heat: Initially, we can set the heat to zero everywhere. No combustion has taken place, and so it's cold. [fire_o1.jpg] Oxygen: Here's blue will be used to show where there is oxygen. [fire_f1.jpg] 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. Burn Step Now, we shall make the three arrays interact. You may remember a little from your chemistry classes (I certain ally remember very little). The rate of a reaction depends on the concentration of the reactants (oxygen and fuel in this case) and the temperature. It also depends on the barrier energy of the reaction. If the temperature is too low, then the reaction will not take place. The faster the reaction proceeds, the more heat is created, and the faster the reactants are used up. So, a stylised reaction algorithm is the following: 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 A nd 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. [fire_h2.jpg] Heat: A small amount of heat generated in the reaction. [fire_o2.jpg] Oxygen: Oxygen around the fuel used up. [fire_f2.jpg] Fuel: No fuel left. Convection Now that we have some heat, we can use this to cause convection. The relative temperature can be directly translated into convective forces (we're assuming that ambient temperature is zero, so relative and absolute are the same). procedure setForces for every pixel i { velocity_vert[i] += temp[i] * Convectivness Cau se convection (up is positive) velocity_vert[i] *= velocity_damping Add a little damping for stability velocity_horiz[i] *= velocity_damping } end of procedure Now, I'm afraid, this is the step I'm going to mostly leave out. This is an article about adapting a fluid simulation to render flames, not one about fluids themselves. I'm going to assume you already have an engine for simulating fluid. If you want to write your own simulation, here are some excellent Papers by Jos Stam. Gas Expansion You'll remember from physics lessons that when you change the temperature of a gas, then it's pressure will change. So if it's not enclosed in a rigid container, it's volume will change also. pressure = temperature volume 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. Rendering The accurate rendering of fire is just as important as simulating it's motion. Why is fire that colour? 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 (l), given off at a particular temperature (t) is given by the Planck Energy Distribution Equation, also known as the Black Body Radiation Equation: power = 2phc^2 l^5(e^(hc/lkt)-1) h = Planck's Constant: 6.626 x 10^-34Js c = Speed Of Light: 2.99 x 10^8m/s l = wavelength in metres k = Boltzmann Constant: 1.38 x 10^-23J/K T = Temperature in Kelvin [lightpw2.gif] On the left, you can see a graph showing the distribution of wavelengths of light given off by an object at various temperatures. At a cool 4000°C, the light is fairly dim, and mostly in the red region. By the time you get to 5750°C, the light is very bright, and has a slight blue colour. Therefore, for any temperature, we can calculate exactly the colour and brightness of the flame. All we need to know is the wavelength of red, green and blue light: Red = 700 nm Green = 560 nm Blue = 470 nm 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 10^8 k = 1.380 x 10^-23 red_wave = 0.70 x 10^-6 wavelengths of red, green and b lue light grn_wave = 0.56 x 10^-6 blu_wave = 0.47 x 10^-6 exposure_level = 50.0 Camera exposure level (see exposu re function) procedure lightpower(wavelength, temperature) L = wavelength T = temperature power = L^5 * e^((h*c)/(k*T*L))-1) power = 10^-28 / power I haven't bothered with the corr ect numerator, I just chose something to give val ues 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 Notice the use of the exposure function. The range of a large range of brightnesses will be emitted by the flames, and so you will need to use the exposure function to bring them within range of your monitor. If you don't, you'll end up with a washed out image, lacking the detail in the darkest and brightest areas. Find out more information about the exposure function. And after all that, your spectrum should look something like this: [Spectrum.jpg] Smoke If there is insufficient oxygen, and if you assume your fuel is carbon-based, then any unburned fuel should become smoke. Cooling Aside from the colour of the flame, Planck's formula also tells us exactly how much energy is being given off in the form of radiation. And so we know the rate of cooling of every part of the flame. The rate of cooling by radiation is proportional to the fourth power of the temperature. Rate Of Cooling = R * T^4 Where R is some constant which can be fiddled with. The important thing is that the cooling follows the fourth power law. Altogether Now 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 Demo Now, I'm still playing around with this, but I thought I'd put it up anyway. I wrote this simulation based on the code published by Gustav Taxén, and added the above algorithms. It seems to work OK; you can imagine you're looking at a large bonfire, and it's mildly convincing. Though not quite the small flame I had been hoping for. In fact, to be honest, it's pretty lame, and need a much better fluid simulation. 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: When you run the demo, drag the control window out of the way, then press "Ignite". [firedemo.gif] Download fluid_fire.zip: 482kb. Windows _________________________________________________________________ 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. _________________________________________________________________ Return to the Good Looking Textured Light Sourced Bouncy Fun Smart and Stretchy Page. © 2003 Hugo Elias