To penetrate and dissipate these (ingame) clouds of darkness, the general mind must be strengthened by education. – Thomas Jefferson
This time I’ll write a bit about our upcoming real-time volumetric cloud system. Unless something goes horribly wrong and the sky is falling down the new clouds should make an appearance in the Jefferson build.
About a year ago I wrote the code and shaders for the current cloud system, that uses sprites to render the clouds seen in the action game. At that point I was already pursuing various options for rendering clouds in a different way, that I wasn’t satisfied with the quality and performance I could achieve using sprites, but due to lack of time I had to let go of the research and use the sprite system.
Recently I watched a demo of the game Arma III and was impressed by the quality they’d achieved and by looking a bit closer I could see they were using a similar system to one I’d thought about back some time ago, and apparently they had been able to solve some of the problems I ran into at that time.
So what did I try?
Back when I started working on the clouds we had a simple sky dome, with a picture of a sky painted onto it. Although it looked fine (with high enough resolution), we wanted to have something more for our dog fights with the planes. We wanted to be able to play cat and mouse with the planes by using the clouds as a cover. For that we required some kind of volumetric representation of the clouds so we could fly into them. Having the clouds painted onto a sky dome just didn’t do it…
Searching the net I bumped into an article by Nianine Wang who wrote the paper “Realistic and Fast Cloud Rendering” about the solution she chose for Microsoft Flight Simulator. I really liked the simplicity in the model, but I wanted to have something that required a bit less artistic input, so we could achieve a larger variety of clouds and weather settings, and also something that better mixed with the atmospheric model I’d made at that point. So I searched on and read the articles by Mark J. Harris, who again referred to Dobashi, where I read about the Cellular Automaton to simulate cloud forming. I liked the idea of using the CA to build clouds dynamically, as that could be controlled by a few parameters, but I needed something that could scale from clear sky to fully overcast, instead of only working for a single cloud.
I ended up using a single 3D volume (volumetric) texture as base for a variation of the cellular automaton – and now the real challenge started – displaying this volume in the game.
First I tried just to slice the volume using planes parallel to the camera front plane and it looked fine until you started to translate or rotate the camera. The movement caused a lot of shimmering when the planes moved around in the volume. I tried locking the planes to a world grid, and although it fixed the problem when translating the camera it still had shimmering when rotating the camera.
At this point I was running out of time for this feature, so I chose to pursue a different path where I would scan the volume cells and generate a number of sprites if the cell was occupied with cloud data. This was the solution that has been in the game up until now, although I wasn’t satisfied with it, due to how it looks and how it performed.
After watching the alpha for Arma III, I got inspired and went back to the drawing board to see if I could solve the problems with the shimmering. I came up with a simple idea of instead of drawing planes, I would draw spheres/shells centered at the camera instead. This turned out fine and solved the problem with the camera rotation, but the problem with camera translation came back. I tried various ideas of snapping and translating the spheres until I ended up with just keeping the centre at the camera but shrink/grow the size of the sphere proportional to the camera translation perpendicular to the front plane. Eg. if the camera moved 5 meters forward I would shrink the shell radius with 5 meters, so that the point on the shell directly in front of the camera would stay at the same position in world space, and if the camera moved 5 meters backward I would grow the shell radius with 5 meters. When a shell became too small I would just remove it and a new shell furthest out, and vice versa in the opposite direction.
To increase performance I tried to combine low resolution rendering with a bilateral upsampling filter, but performance didn’t increase as much as I would like because of the increased cost of doing manually depth testing in the clouds shader, and from the upsample filter cost.
Instead I went with the simple solution of just adjusting the number of shells based on the quality selected by the player. To further increase performance I reduce overdraw by clipping the shells against the top and bottom of the cloud layer. But there still room for improvement.
Without adding noise to the clouds look they look quite bland so to improve the visual look of the clouds I add a translate the volume lookup coordinates with an offset sampled from a Perlin noise volume using a scaled version of the texture coordinates used for the clouds volume like this:
float4 vNoise = SAMPLER3D_SAMPLE(PerlinVolume, vNoiseCoords * fFractalScale) - 0.5f; vNoise *= fFractalStrength; vTexCoords.xyz += vNoise.xyz; float4 vSample = SAMPLER3D_SAMPLE(CloudVolume, vTexCoords.xyz);
Without noise the clouds look like this:
To give the clouds a more volumetric shading I use an exponential falloff based on the density from the point in the cloud towards the sun. In praxis this is implemented as sampling a with a fixed distance from the point in the cloud until exiting the cloud layer. Additionally I add fog and Rayleigh scatter based on the direction of the sun to get the final look.
Although this post has been a lot more technical than most of our posts I hope that you have found it interesting to see a bit more about what is actually happening when you fly a plane through a cloud.