Hi,
Decided to toy around with clouds yesterday, ive been meaning to for a while now every since I saw the Far Cry videos and such. I read a few articles that seem to over complicate things; for example this tries to mimic realistic cloud behaviours such as the probability that water vapour will go to water droplets when the pressure falls before a certain level. However, it also allows “shaft light” phenomenon to occur. this also doesn’t allow light to move around freely without oncurring heavy computation, however, it does use naiver stoke equations to solve densities at certain points (from what I can understand from it) and is thus more accurate than my method, but its about 100x harder, it also doesn’t allow for “shaft” light, whereas my method does.
Fudge all that!
What I did was rather simple, and produces good enough results for games, worst case scenario, it produces as good results as 4d perlin noise. This is the algorithm; note that im going to be talking about 1 cloud at the moment, but the algorithm can be extended for N clouds and the clouds to merge together upon collision. Also, im going to describe the method that works without shaders, although with shaders, its still simple, and is probably faster.
Algorithm
- Create a 3D grid (that will be converted to a 3D texture).
- Create N point masses, try and keep them initially together within the regions of your cloud, a pseudo-random generator should do the trick fine. These point masses have a mass and a constant C.
- Loop through every cell in the grid and find the nearest point mass.
- Set the value of the current grid to be equal to NearestPoint.C * distanceToNearestPoint (this is effectively a voronoi diagram with 1 distance function).
The above will create clouds that are ok looking, if you get you constant C right, all is nice, you have to experiment a little to get that nice fluffy feeling of clouds.
- Using some movement function, be that a simple x += velocity, or complicated fluid dynamics, move the point masses along and update the field, this will cause the animation of clouds. Obviously, if you used fluid dynamics, the animation of the clouds is realistic, but a verlet integrator taking into account influences from other point masses around it would work well too; a mixture of force and point gravity.
- Vary the C constant with a probability function, what you effectively doing there is increasing the probability of water vapour changing to water droplets and vice versa thus creating and destroying clouds. A 1/x function is a good decay algorithm, simple and produces nice results too.
Rendering the actual clouds can use anything really, marching-cubes algorithm for volumetric tesselation is good, but since I already have the 3d grid, i just converted that to a 3D texture and did a glTexSubImage3D on updates, pretty nifty. Shaders are also possible, you can calculate the voronoi diagrams and do the calculations on a per-fragment bases, just pass the point masses in as uniforms. Its better off splitting the point masses into grids and using the hanging-moss algorithm before passing the uniforms to the shaders.
Shaft Light is pretty simple with grid based approach. In the 3D texture, add a light factor to every cell, then when sample the light and attenuate the light factor from the cells above it (above, above left and above right cells, scale down the left and right too). You then have the silhouette to extrude the shaft from, use the common stencil shadows alogrithm for extrusion and stencil masking.
If anyone has any improvements, let me know.
DP