Let It Snow!

Hello! This is John, and I'm using today's #screenshotsaturday to talk technical.

Something that we've received positive feedback on so far in developing Fantastic Jack is our swirling snow particle simulation, and I'm proud of how that turned out, so I wanted to explain how it works.

Particle systems are a common feature of video games, used for animating dust clouds, raindrops, fire, sparks, and other amorphous phenomena. The technique is simple: just keep track of the center positions of all of the particles, move them all a little bit each frame, and then draw a speck on the screen for each of them.

Usually particles are spawned with their own position, velocity, decay, and other parameters, at which point they move independently for a period of time before evaporating entirely. In a vacuum, that would make sense; but in real life, particles are usually surrounded by air, and air is a fluid that influences their motion. Small particles like snow have very little mass and a lot of air resistance, which means that instead of cutting through the air, they tend to move with the air, revealing the underlying air currents that would otherwise be invisible to the naked eye.

So what do air currents look like? Well, as any meteorologist could tell you, air currents can be extremely complex, chaotic, and hard to predict. But we're not actually trying to represent full weather patterns. We just want a way to move all the particles somewhat randomly but also in a way that's "natural-looking" as they fall to the ground. Fortunately, there exists a simple approximation that looks good enough for our purposes, and it's called "curl noise".

The word "noise" is usually associated with discordant sound effects, so it might seem like a strange connection, but sound isn't the only thing that can be noisy. Noise is just a disturbance of random-ish waves. It just so happens that random sound waves are a defining characteristic of cacophonies, hence the name noise.

Curl noise is an extension of more popular noise patterns like "Perlin noise" and "value noise". I was first introduced to noise patterns with Photoshop's "Clouds" filter. Similar noise patterns are often used to make artificial mountain ranges in computer graphics by using the noise as an elevation map. The introductory videos for Shadershop happen to be a great demonstration of how a program can generate such noise.

We can write a program that maps each snow particle's current position to somewhere in the noise field and use the noise value at that position to determine where the snow should go, but it's not immediately clear how to do that. The noise only gives us one numerical value at each position, but we need both a speed and a direction for each particle.

The first trick we use to solve this problem is to notice that, in addition to a value, every position in the noise field also has a slope. We can check neighboring positions to the north, east, south, and west to calculate the slope, and that slope has both direction and magnitude. If you think about the noise as an elevation map with water particles on it, you would expect water to run downhill and the simulation could use the slope of the noise to determine how to move the water particles.

But there's a big difference between water moving downhill and particles in the air. Water collects into pools in the valleys and stops there. Air currents, however, maintain a relatively even distribution of air pressure, constantly moving without collecting in any one place. We need a somewhat random direction to move the snow particles in that won't eventually leave them all clumped together before they even hit the ground.

Fortunately, there's one more trick we can use to model air currents more accurately: rotate the slope 90 degrees before letting particles move along it. In other words, instead of using (dx, dy) as the direction, use (-dy, dx).

This is actually really elegant, but to understand why, we need to go back to the elevation interpretation. The slope reveals exactly which direction to move a particle in if we wanted it to go uphill or downhill, but we know that if we keep doing either of those things, it'll eventually end up getting stuck at a valley or peak. However, as long as the particle never goes up or down, it can keep going forever. Imagine drawing the elevation as a topographic map with curved lines drawn at each elevation level, looping around peaks and valleys. Moving perpendicular to the slope means following along one of those lines, circling endlessly.

This is what curl noise looks like, but there's still one more problem. The snow particles never cross paths. Our falling snow uses one last trick to look more convincing, which is simply to use a 3D noise field instead of a 2D one. The game may be 2D, but real air currents are 3D and we expect to see a bit more parallax as snow in the foreground and background move in different directions. It's a lot harder to visualize the interior of a 3D noise field, and the slope rotation is a little more complicated in 3D, but the idea of moving perpendicular to the slope while maintaining an elevation is the same. For reference, the 3D slope rotation is (dz - dy, dx - dz, dy - dx). Of course, if you want to be confused, feel free to check out the Wikipedia article on this curl operation!

Thanks for reading!


PrintView Printer Friendly Version

EmailEmail Article to Friend

References (29)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
« Worlds Apart | Main | Hello World! »