There's sure a lot of academic papers on implementing atmospheric shaders. The one thing that each paper has in common is math. A lot of math. With scary summation and integral symbols. All of this stuff was overwhelming; my math knowledge is limited to first-year calculus.
One of the things I learned from GPU programming books is that the rendering techniques don't have to be mathematically correct; it just has to look correct. So I just kludged together something that kind of looks right. It's definitely nowhere near as nice as some of the atmospheric shaders out there, but it's better than OpenGL uniform fog.
The Land-o-Rama atmospheric shader implements a simple height-dependent atmosphere. The atmospheric density falls off exponentially with increasing altitude. It doesn't take the view direction and the sun angle into account, so it doesn't render a cool red sunset or a light bloom around the sun. Someday, I'd like to do this though.
First thing I needed to figure out was how to calculate atmospheric density along the view ray. Looking through the paper Real Time Rendering of Atmospheric Scattering Effects for Flight Simulators by Ralf Stokholm Nielsen, I found out that it's surprisingly easy to do this. First, you measure the atmospheric density at the eye and at the vertex to draw. Then, you take the average of the two densities and multiply it by the ray's length. That's it! (You can also raise e to the power of this value to have exponential fog.)
Next, the shader calculates the atmospheric inscattering factor. This is the amount of light that is added to the view ray from outside sources, like the rest of the atmosphere. To do this, the shader simply multiplies the view-ray density by the sky color. (I used a bright blue in these examples.)
Next, the shader calculates the atmospheric extinction factor. This is the amount of light that is absorbed along the view ray. To do this, the shader multiplies the view-ray density by the inverse of the sky color. (The inverse of the sky color for a bright blue sky is a dark orange.)
To find the color of the vertex, the shader multiplies the terrain color by the extinction color, then it adds the inscattering color. That's the final color.
Here's a screenshot of this atmospheric shader.
Compare it to the screenshot from the previous journal entry.
Here is a bird's-eye view of the terrain. The yellow dot is the current position. Note the atmosphere gets bluer and more hazy with increasing distance.
Here's what happens when you increase the atmospheric density, increase the density falloff factor, and change the atmosphere color to white:
There's now mist in the valleys.
The next thing I worked on was adding per-pixel bump mapping. This also gets rid of the cross-shaped artifacts that you can see on the left side of the first image.