26 2.Modeling,Lighti ng,andRenderingTechniquesforVolumetricClouds
,,abc are the semiaxis lengths of the ellipsoid. Subtract this expression from
one to modulate the phase and vapor probabilities with distance from the ellip-
soid center. As an optimization, the cellular automaton may be limited to cells
contained by these ellipsoids, or each ellipsoid may be treated as independent
cellular automata to eliminate the storage and rendering overhead of cells that are
always empty. If you’re after cumulus clouds with flattened bottoms, using
hemiellipsoids as bounding volumes for the clouds instead of ellipsoids is also
more efficient.
You may grow your simulated clouds by placing a few random phase transi-
tion seeds at the center of each ellipsoid and iterating over the cellular automaton
a few times. The resulting 3D array of cloud states may then be stored for render-
ing, or you may continue to iterate at runtime, smoothing the cloud states in the
time domain to produce real-time animations of cloud growth. In reality, howev-
er, clouds change their shape very slowly—their growth and extinction is gener-
ally only noticeable in time-lapse photography.
SimulatingtheDistributionofClouds
We discussed using bounding ellipsoids to contain individual clouds within our
simulation, but how do we position and size these ellipsoids? Some approaches
leave the modeling of clouds entirely to artists or level designers [Wang 2004],
but procedural approaches exist to make the generation of realistic cloud volumes
easier. The Plank exponential model [Plank 1969] is one such technique, based
on the analysis of experimental data of cloud size distributions over Florida.
Plank found an exponential relationship between cloud sizes and their densi-
ty in a region of cumulus clouds; further, he found there is an upper bound of
cumulus cloud size at any given time of day, and there are fewer of these large
clouds than smaller clouds.
His algorithm may be implemented by iteratively calling the
GetNext-
Cloud()
method shown in Listing 2.2 until it returns false. GetNextCloud() is
assumed to be a method of a class that is initialized with the desired cloud cover-
age, area, and minimum and maximum cloud sizes. For the constants referenced
in the code, we use an
alpha value of 0.001, chi of 0.984, nu of 0.5, and beta of
0.10
. We use a minimum cloud size of 500 meters, a maximum of 5000 meters,
and an
epsilon of 100 meters.
bool GetNextCloud(double& width, double& depth, double& height)
{
while (currentN >= targetN)