Thursday, August 20, 2015

Volumetric Clouds

Awhile back I wrote a system to create and render a volumetric nebula for universe mode. Later I realized that a modified version of that effect also made a good debris/dust cloud for ship explosions. Then I used a more colorful version for teleporter graphics in ground gameplay mode. This week I decided to try this approach for rendering volumetric puffy clouds in infinite tiled terrain mode, and it works! Well, almost, they don't quite look like "normal" clouds from a distance but they look great up close. Plus, the player can fly through them.

Before I show you some pretty screenshots, I need to get some technical details out of the way. I'll try not to make it too bad for the nontechnical readers.

The volume cloud system I'm using isn't actually something I thought up myself. I saw it explained in a video that I found on YouTube through a Google search a few years ago. Unfortunately, I can't seem to find that video again, so I can't link it here. The video described how to create a nebula out of a number of randomly oriented 2D slices containing partially transparent plasma textures created in Photoshop. Since I needed one unique nebula per galaxy, in a game with an infinite number of galaxies, I had to do something a bit different. Instead of manually creating an infinite number of textures in Photoshop (which I don't own), 3DWorld generates the color and alpha (transparency) values directly on the GPU using random 3D noise textures to create ridged Perlin noise. The location of the nebula in space is the seed used to determine the starting and step direction/distance into the noise texture so that each nebula is unique.

Each particle cloud (nebula, etc.) consists of 13 2D quads (squares) that all intersect at their centers. Each quad can be viewed from either direction, so it's actually more like 26 2D billboards. The quad planes are oriented in uniformly distributed directions by taking all {x,y,z} values in {-1,0,1} and folding out the symmetric ones. This gives the following 13 directions before normalization: (1,0,0), (0,1,0), (0,0,1), (1,1,0), (1,0,1), (0,1,1), (-1,1,0), (-1,0,1), (0,-1,1), (1,1,1), (1,-1,-1), (-1,1,-1), (-1,-1,1).

The corners of the quads are attenuated to an alpha of zero (fully transparent) so that they appear as circles with a smooth falloff from opaque to transparent at their outer edges. In addition, quads that are nearly parallel to the view direction are faded to transparent to avoid ugly artifacts from looking at them edge-on. Then the color and alpha channels are modulated by the noise functions to give an interesting, cloud-like effect. The fragment shader evaluates the noise function at a position corresponding to the coordinate of each pixel on the quad in 3D world space. Therefore, the cloud looks correct and has proper parallax when the viewer/camera moves around and through it. That is, as long as the view doesn't pass directly through the center where the quads all intersect, which is a singularity where every quad is viewed edge-on and rendered invisible, causing the cloud to disappear. I guess that's what it's like to be in the eye of the storm.

Here are some of the fun things I can render using this system.

Yes, it can draw a nebula, what a surprise! This system was initially used for drawing nebulae in universe mode. I've shown this image in a previous blog post, and here it is again.

Closeup view of a procedurally generated nebula in universe mode. This was in a previous blog post.
A nebula is drawn using ridged noise (just Perlin noise with some extra math). Okay, if you're curious, here is the math that converts a Perlin noise value 'v' into ridged noise:
v = 2.0*v - 1.0; // map [0,1] range to [-1,1]
v = 1.0 - abs(v); // ridged noise
v = v*v; // square it

Yes, exciting, isn't it? The nebula shader uses two random noise color channels where the colors themselves are also randomly selected (I think it was pink and orange in the screenshot) + one alpha channel. The noise is mostly high frequency and the bounding shape is spherical.

Who creates a space game without ship explosions? What is left after a big ship's explosion, anyway? A cloud of glowing dust and particles! This can be drawn with the same technique. Just use lower frequency noise to make it more irregular, make it even more ridged and wispy, use different colors for the interior vs. exterior of the volume, and you get this:

Volumetric debris and dust cloud from blue/white and red/orange ship explosions in universe mode.

That's enough particle clouds in universe mode. It looks good, but I don't want to overuse the effect. Where else can it be used? How about using it for the new teleporters in 3rd person shooter ("ground") mode? Since a teleporter doesn't exist in the real world I can make it look however I want. I decided to make it very bright so that it stands out, adds color to the dull grays of my office building scene, and looks like something that is definitely not natural. The colors and noise are animated as well so that it's clear to the player this thing isn't just a static decoration. It draws attention - this glowing object does something. Teleporters use 4 high frequency ridged Perlin noise channels in the shader: red, blue, orange, and alpha.

Closeup of a teleporter gameplay entity. The dynamic, animated, colored cloud casts light on the ground.
Here is a short video of the teleporter in action, where you can see the animated colored volume and how it actually moves the player to a different location in the scene. Note that teleporters don't just work with the player: they work with enemies, items, projectiles, particles, and any other type of dynamic game object. It's fun to throw grenades into the teleporter trying to hit someone you can't see on the other side. Just make sure you count to 5 before walking into it yourself. Sorry, I didn't record a video of this (yet).

The obvious use for a volumetric particle cloud rendering system it for rendering ... clouds. There are a ton of competing ways to draw clouds in games. Sometimes clouds are meant to be viewed from below, for example when the player can walk or drive on the ground. Sometimes clouds are meant to be viewed from above or inside, for example in a flight simulator or space game. In 3DWorld, there's really no constraint on where the player can go. It's a game engine, not a game, so it could be used for a ground-based first person shooter or a flight simulator. These clouds need to look correct, with a good frame rate, when viewed from any location. Well, except from their exact centers (again).

Clouds are drawn in a base color of white but are modulated to match the lighting conditions so that they're red-orange during sunrise/sunset and dark gray at night. Their brightness decreases toward their center to simulate self-shadowing inside the cloud volume. I haven't yet tried to add light scattering to these clouds. In addition, they become opaque near the center where the noise value has less of an effect. They use regular Perlin noise rather than ridged noise for a more puffy and natural appearance, and have a mixture of high and low frequencies. The noise function offset varies slowly so that clouds change shape over time. Here are some clouds viewed from the ground below in infinite tiled terrain mode.

View of volumetric procedural cloud puffs from below. These clouds slowly change over time.
Tiled terrain mode actually draws three cloud layers (listed in the order in which I added them):
  • 2D procedural noise cloud plane. The terrain and grass shaders ray cast into this layer for soft cloud shadows. I also have slow God-rays that ray march through the cloud density function. Density depends on weather conditions and atmosphere. Slowly animated/scrolling.
  • Static textured upper cloud layer. Provides a more interesting background than pure blue.
  • Puffy volumetric clouds. The new mode that's the subject of this post. Doesn't cast shadows yet - unclear how the terrain and grass shader can ray cast into these. Animated, but more slowly.
The sky looks a bit cluttered with all three cloud layers enabled now. Also, it's odd that the first layer casts shadows, but the second layer (which is denser and more apparent) doesn't cast shadows. Maybe I'll remove the first cloud plane layer later. Or maybe the set of enabled layers should be determined by atmosphere and weather conditions. For example, use a large number of puffy gray volume clouds when it's rainy, but only sparse/high 2D cloud cover when it's sunny.

This wireframe view of clouds from above shows how they are composed of multiple 2D quad billboards in various orientations arranged around a common center point, similar to flower petals.

Clouds drawn in wire frame mode. The structure of the 13 intersecting planes can be seen.
Here is a short video of the player flying through the cloudy sky over some islands. Since the clouds are rendered in 3D, they appear as real volumes when flown through. Most games seem to use 2D cloud billboards or skybox background images that are only meant to be viewed from a distance.

So far I've come up with four different uses of this particle cloud rendering technology. I wonder what else I can use it for? Rocket explosions? Plasma balls? Smoke effects? Insect swarms? Actually this might work well for smoke, and could be a good replacement for the existing billboard cloud system I use for smoke in 3DWorld. I guess we'll just have to wait and see.

No comments:

Post a Comment