Simulating gases using a procedural material

by François Guillet

This tutorial owes a lot to "Texturing & Modeling A Procedural Approach" by Elbert, Musgrave, Peachey, Perlin, Worley Morgan & Kaufmann

 

 

In this tutorial, I will illustrate how gases or gas-like environment can be simulated using a procedural material. We will address two effects such a volume has on light:

-absorption

-scattering

 

Absorption is directly related to the density parameter of a material. When the density increases, so does the material light absorption : it becomes more and more visible. Scattering means that each point of the material scatters incoming light, thus becoming a tiny point light source itself. This probably explains why this feature costs a lot in terms of rendering time. Some systems, like dust in a house, do not show up until directly hit by sun rays. This probably means that absorption is not the main characteristic of this phenomenon, but rather scattering. On the other hand, some other phenomenons, like water vapor rising from a cup of hot water, cause light absorption.

 

Anyway, when simulating gases, both parameters often vary in space: the effect is not uniform. As soon as a property is not uniform over a whole volume, a procedural material has to be used. In the following examples, we will try to simulate vapor raising from a cup of hot liquid in different ways.

 

The first step is to create a sample scene with a cup and a dummy object to host our effect through its material:

 

 

In this case, the dummy object will be a cylinder in which the vapor will “rise”. In order to control of x,y,z coordinate ranges, it is best to convert the cylinder to a triangle mesh and have the vertices coordinates start at y=0 as shown below. This will be helpful when we’ll use the coordinates to determine density and scattering.

 

 

We now have to calculate vapor density inside this volume. Quite obviously vapor density is maximum just above the liquid surface and near the center of the cup. Roughly, steam occupies half a sphere above the cup. It is maximum at the center of the sphere and radially decreases. It also has a “nebulous” aspect which is quite well approximated by the “Turbulence” procedural motif. Turnulent module default parameters will be used, except an amplitude of 1.7 instead of 1 which will make the turbulent gas 'thicker'. We also have to determine a density for each x,y,z point and multiply this density with the turbulence motif. The density has to be one at x=0, y=0, z=0 (the bottom of the cylinder) and falloff radially. This is done using the following procedural material which has to be assigned to the cylinder. Also, do not forget to use a totally transparent texture for the cylinder as well.

 

gas_fichiers/image009.jpg

 

The principle of the procedure is to calculate the distance from the x,y,z  point to the origin. The double of this distance is subtracted from one in order to decrease density which must be zero or negative when the cylinder boundary is met (a density or scattering below one will be interpreted as null). The result is multiplied by a turbulence motif, and plugged in Density and Scattering parameters (depending on what you really want to do, different results could be used for one parameter or the other). You may use any one of these two or a combination as you see fit. The render shows a tiny hemisphere of vapor above the cup. Whereas this result is OK in the x,z plane, the vapor is expected to rise higher along y direction. A solution is to confine the vapor not within a sphere but whithin a taller ellipse. This is simply done through altering the procedure as shown below. The 0.3 scaling factor on Y ensures that the ellipse is 1/0.3 taller than the sphere.

 

gas_fichiers/image013.jpg

 

That’s more like it! But in fact, we would expect the steam to “expand” above the cupas disperses. A solution is to use a cone instead of a cylinder and have the vapor fill this cone. However, we can’t really modify our mathematical ellipse to fill the cone. We will switch to a formula that suits the conical shape. The first step is to transform the cylindrical triangle mesh into a cone. Next, the material procedure is modified as shown below.

 

 

 

Only the radius in the x,z plane is computed. This radius is multiplied by a negative quantity which increases (absolute value decreasing) as y increases. The 0.7 coefficient makes it increase slower because preliminary tests showed that conical expansion was too fast. As a result, density decreases less when computed far from the cone center when y increases. And here is the render:

 

gas_fichiers/image018.jpg

 

Obviously, there is far too much steam at the top of the cone. It should be less dense as it disperses. So we will introduce another correction which will diminish density as a function of y. After some trials, I came up whith a 1/(y+1) decreasing function. I scaled it to 1/(1/3*(y+3)) after final tuning. The point is that the function must decrease as y increase. It must compensate a volume increase by y due to the cone (y cone slices volume increase linearly with y). So steam volume increase as y and it must be multiplied by 1/y to be kept constant. Since the function must yield a density of 1 at y=0, the function to use is something like 1/(y+1). Here is the actual procedure used, and the resulting render:

 

 

gas_fichiers/image002.jpg

 

The result is fine, but it can be further refined (or complexified) with the consideration that the steam does not rise in a turbulent way when it is just coming up from the cup. It is first homogeneous and then becomes turbulent. This effect can be simulated through adding a fraction of constant density steam to the complementary fraction of turbulent steam. Say that at some point y we decide to have a p fraction of turbulent density steam, then:

 

Total stream = ( 1 - p )* constant density steam + p * turbulent density steam

 

Of course, p is a function of y and reaches 1 at some point. After that point, it remains constant at this value. We will use a cutomized function to define p=f(y). The final procedure is thus:

 

It is admittedly complex. First we use  the 0.7*y value that has already been used before to fill the cone with steam. This value is input in a customized function that is reproduced below. Please note that this function output doesn’t start at 0 but at 0.6. Values below that generate far too much steam, and in fact a majority of turbulent steam is already needed at y=0. It reaches 1 (fully turbulent steam) when 0.7*y = 1. the resulting value p is multiplied with the turbulent motif and 1-p is added to the result.

 

 

The result now looks like this:

 

gas_fichiers/image040.jpg

 

 

Of course, I do not claim that this procedural material is the best one for simulating steam over a cup of coffee, but this shows you what can be done using procedural materials.


File for spherical steam can be downloaded here:
Steam_sphere.aoi

File for conical steam can be downloaded here:
Steam.aoi