[Bf-cycles] Fire + smoke rendering

Brecht Van Lommel brechtvanlommel at pandora.be
Sat Mar 29 15:37:36 CET 2014

Hi all,

Cycles now has some basic support for accessing fire and smoke data,
but more work is needed to get great looking renders and a good
physically based shader. Here's a basic example shader but it doesn't
look particularly good:

In case someone likes to work on a better shader, or wants to work on
other improvements in this area, here are some notes.


In these course notes, "4.5. Blackbody radiation" in "Volume Rendering
at Sony Pictures Imageworks" seems to be a good practical reference
for implementing a fire + smoke shader:

Also good papers:

Following the "Physically Based Modeling and Animation of Fire" paper, we need:
* Smoke: volume scattering and absorption
* Fire: volume emission and absorption

The trick is getting the fire and smoke data converted to parameters for these.


For smoke we need a scattering coefficient sigma_s, absorption
coefficient sigma_a. For Cycles you would add a scattering and
absorption node which take color and density as input, and it will
internally compute the coefficients like this:

* sigma_s = color * density
* sigma_a = (1 - color) * density

The coefficients and density both have units m^-1 (assuming you have
metric unit scale set to 1.0 in Blender).

For Blender Internal there is a Smoke grid that gives RGB (color) + A
(density). The density is "premultiplied" into the color, and then
after interpolation unpremultiplied, which avoids zero density areas
incorrectly darkening the color. The density here is assumed to be
m^-1 and matches Cycles.

The OpenGL smoke preview however does not match Blender Internal. It
has a different interpretation of the density, and in fact has a bug
where scaling the domain object will change the density. Even with a
1x1x1 sized domain the density is wrong. It draws 128 slices but
doesn't seem to divide by that number anywhere to compensate.

The result is that if you simulate smoke in the viewport and want a
similar looking render you need to multiply the density by 10x-100x to
compensate. It would be good to fix the OpenGL preview and change the
defaults so you get a denser smoke.

Overall this should map pretty well if you pick the right scattering
anisotropy and don't worry too much about the density mismatch with
the viewport.


For fire we need an absorption coefficient and emitted radiance.

The OpenGL preview ignores absorption for the fire, and the emitted
radiance is computed from a "flame" field which seems to have values
0..1 that map to temperatures 1500..3000 K. The alpha here is computed
such that it fades from zero to one between 1541 K and 2086 K, to get
a smooth transition. The temperature is converted to an RGB color
using a blackbody function (one with chromatic adapation, not sure if
this is the same one as we have in Cycles).

For Blender Internal the user is expected to do something similar but
manually by using the Flame grid and mapping it with a custom color
ramp with blackbody like colors and alpha to get a smooth transition.

So the situation here is less clear than for smoke. First we need some
mapping from this 0..1 range to temperature, maybe someone can look
into the smoke simulation code to shed light on this.

Once we have the temperature we can use blackbody formulas to convert
that to colors. We have a blackbody node but lack a builtin way to
compute the blackbody intensity. This can be done using the
Stefan-Boltzmann law (see course notes).

For absorption of the fire, I'm not sure how to pull that out of the
smoke sim. Maybe it doesn't have a big effect if the emission
overpowers everything.


More information about the Bf-cycles mailing list