Dynamic 3D clouds + shading model?

Hi all,
as my first post here, I would like to know if someone already implemented (and would share experience/best practices/sources) 3D clouds + volumetric shading (isotropic or anisotropic)?

I’m currently working on a game spin-off and so far, I’ve got only a blue sky with a sun (implementation of “GPU Gems 2, chapter 16 - Accurate Atmospheric Scattering”) 8)

http://tf4r.googlecode.com/svn/wiki/img/screenshot%20level%203%20-%20atmospheric%20scattering%20effect.jpg

I’ve started the implementation of the following paper: “Realistic and Fast Cloud Rendering” but as it is old (2003), I was thinking about posting here before.

Notes:

  • the sources of the project are available (for free) to everybody interested
  • I’m looking for opengl 2.0 (max.) implementation for compatibility
  • a video of my WIP (poor sound quality :frowning: )

Thanks in advance for your help.

Regards,
WS

Hi!

Where is the source code? Thanks for sharing.

For this effect: you have the source code (not cleaned) here.

For the game levels, I’ll have to upload it (soon) on google code (so be patient :wink: please)

WS

Does it need to be realtime, as in moving clouds, or would you accept billboards?

This is what I cooked up years ago:
http://indiespot.net/files/cuage/

Hello Riven,
I indeed intend to at least animate them as explained in the paper (dissipation, colors changing). I did not precise but the code on the LWJGL forum is an animation as the sun is slowly disappearing behind the ground producing a cool sunset thus the colors must be also dynamically set. Finally with a shading model (not necessarily complex) the effect will be great.

Note: in the beginning of this level, some ennemy armada will appear behind and through distant clouds.

Anyway the pictures are cool. Do you have one bilboard per cloud? Or are there multiple “particles” possibly animated (RGBA speaking) separately?

Thousands of sprites, that are lit with a volume tracer (sun-to-sprite). It was far from realtime: 45sec per render.

The narrow white smoke column was 2D, mostly faked and realtime though.

Ok, maybe something I could start with :slight_smile: (if you propose to share your code).

I think the paper mentioned above uses the same technic regarding multiple sprites but for the colors, it uses some short-cuts (manually chosen colors). You can see some aspects of another implementation of it (according to me) here (see section “Illumination”).

Looks extremely fake, compared to mine :wink:

Last year, I came up with a much faster algorithm, that I haven’t turned into code yet. The idea is this:

You have a massive grid (both in volume and in memory size). Think of it like: byte[whd]

You image the light-source infinitely far, so all light-rays have the same vector, but different initial positions (as in: directional light).

Every cell in your 3D grid is filled with air/watervapor (determines translucency). Naturally, tracing through this grid for every cell is extremely slow, as you’ll find yourself doing ray-cube intersections. There is a shortcut however:

Take 1 ray, and make its directional vector length tiny (say 0.05, where the grid cellsize is 1.0). Now slowly advance your position and check in which cell you are (casting x,y,z to int). Once you determine you left the current cell, put that cell in a list. After tens of thousands of iterations, you end up with a path with a reasonable amount of integer 3d coordinates. Compare the adjacent coords in the path and you’ll (obviously) see the delta in each axis is either -1, 0 or +1. Put these delta’s into a list.

Now you have a list (or array, for performance reasons) of deltas that allows you to step through the grid at incredible speed, no geometry intersection-checks.

It would look like:


byte[] density3d = new byte[w*h*d];
int[] illumination3d= new int[w*h*d];
int x,y,z;
int[] stepper3d;
int rayLight = 10000;

for(int p=0; ??? && rayLight > 100; p++)
{
    int index3d = (d*width*height) + (y*width) + x; // replace with bit-fiddling

    int density = density3d[index3d] & 0xFF; // 0..255

    int absorb = rayLight * (0xFF-density) / 0xFF;
    rayLight -= absorb;
    illumination3d[index3d] += absorb;

    // follow your stepper, multiple times.
    int step3d = stepper3d[p%stepper3d.length]; // obviously use bit-masking here, not modulo
    x += (step3d / 1 % 3) -1;
    y += (step3d / 3 % 3) -1;
    z += (step3d / 9 % 3) -1; // 0..2 => -1..+1, also turn this into bit-magic

// faster code would look like:
// x += ((step3d>>0)&2)-1;
// y += ((step3d>>2)&2)-1;
// z += ((step3d>>4)&2)-1;
}

Naturally it’d suffer from jittering artifacts, so you create 4 (or more) paths, with adjusted initial position (say 0.5*cellsize).


  |       |              TOP VIEW
--+-------+--
  + x   x +
  +       +              x    means where the 4 paths initiate
  + x   x +
--+-------+--
  |       |

You can use these 4 paths to trace your entire volume (or part of it every frame), by starting at the edge-cells of your 3d grid. It won’t be 100% accurate, but it will be more than adequate.

If you’d wish, you can do a 3d blur as a last step. Now you have the luminance of each cell in your 3d grid. When you place your sprites, you can lookup these values to set the vertex-colors.

Riven, I see your point (although int computing indeed may bring strange artifacts).

Just for me to understand, the massive grid represents a cloud or general atmosphere conditions for the scene being rendered?

BTW, I’ve started to implement the paper and following is my first screenshot (in order to see progression :wink: ).

http://tf4r.googlecode.com/svn/wiki/img/screenshot level 3 - my very first cloud.jpg

I use this texture atlas:

http://tf4r.googlecode.com/svn/wiki/img/screenshot level 3 - clouds atlas.png

Goal, get something like:


http://www.ofb.net/~niniane/clouds/cumulusCongestus.jpg

So a big work regarding shading awaits me…

Hence the blur.

Whatever you want it to be. If you want shading per cloud, you can make a grid for each cloud. If you want clouds casting shadows on other clouds, you should make your grid either huge, or come up with a more efficient datastructure (lots of sub-grids, no hierachy).

Both images fail to load.

Pictures moved to my wiki.

Clouds at sunset…

http://tf4r.googlecode.com/svn/wiki/img/screenshot%20level%203%20-%20clouds%20at%20sunset.jpg

The problem you’re having is that your sprites contain shade. They must be 100% white, only the transparency should vary. Once you get rid of all the baked in shading, it’s time to add your own.

Otherwise every batch of cloud sprites will look like an explosion. (self illuminating)

I guess you are all aware of this?
Quite old, but runs blisteringly fast on modern hardware.

Yes. But you first have to render the images that will be projected on the impostors. In the end you still have to do volume tracing, because everything else looks fake.

I’m not even going to attempt to understand the differences between the volume tracing algorithm you are discussing here, and the various scattering processes highlighted in that article. (which, btw contains the source to the flightsim demomstrating the clouds.)

However the use of imposters removes the necessity for the algorithm to be real-time, doesn’t it?
My understanding is that it gives you several orders of magnitude more processing time with which to compute the realistic lighting.

Indeed! I set them whiter and the result is really better. However one more question regarding the textures used. The alpha channel is derived from luminosity the texture alpha components go from 0 to 255. Should I set it to 255 or 0 only?

And indeed now, I’ve got to work the shading; I’ve thought about you proposal and it may bring good results :slight_smile:

BTW, did you look at Cloudwright?

The tool contains shaders and 3 tutorials explain (in the help file) the different parameters that modify generated cloud appearance.

They seem to use some grid (warping) concept + fractal/marching.

The problem with volume tracing is that even with using impostors, it’s hard to get realtime performance. The clouds are also dynamic, so the impostors have to be rerendered every few seconds.

It’s not a simple problem. Most game engines cheat, with nice, but far from correct results. It’s all about how much priority you give it - faking it often is good enough.

More realistic clouds thanks to whiter textures:

http://tf4r.googlecode.com/svn/wiki/img/screenshot%20level%203%20-%20clouds%20more%20realistic.jpg

Sunset impacting clouds color:

http://tf4r.googlecode.com/svn/wiki/img/screenshot%20level%203%20-%20clouds%20at%20sunset%202.jpg

And now very basic shading (dot product between center cloud to particle vector and center to sun vector):

http://tf4r.googlecode.com/svn/wiki/img/screenshot%20level%203%20-%20clouds%20more%20realistic%20with%20basic%20shading.jpg

Hello sonic,

Have you tried to take a look at “5.3 Volumetric Clouds and Mega Particles by Homam Bahnassi and Wessam Bahnassi” from shaderx5 ?

When you are done, try to add a light scattering effect, I wrote an openGL port http://fabiensanglard.net/lightScattering/index.php, based on GPU Gems 3 article.