Writing / Articles
ArticleCode

Sky like in Crysis: atmospheric scattering

The physics behind a Crysis-style sky: how Rayleigh and Mie scattering shape atmosphere color at different times of day. Work in progress.

Introduction

Rendering the sky and atmospheric effects is one of the more important problems in modern computer graphics. In games, the sky doesn't just convey the time of day — it carries mood, atmosphere, and weather too.

On top of that, the color of the sky affects the final color of objects in the scene: the farther an object (or a piece of terrain) is from the viewer, the more its color gets replaced by the color of the sky. This effect was first described by Leonardo da Vinci and is called aerial perspective. People subconsciously use it to judge the distance to objects they're looking at.

This article covers the physical laws behind the familiar colors of Earth's atmosphere at different times of day, and then applies those laws to implement a sky shader. Two things worth flagging upfront:

  1. There are plenty of articles online covering atmospheric scattering in exhaustive theoretical detail. This one focuses mainly on the practical implementation — the theory is kept to the minimum needed to understand how the final algorithm works and why it produces the results it does.
  2. This article only covers atmospheric scattering and aerial perspective. Cloud rendering, which is technically an integral part of the sky, will be covered in a future article.

Theory

The planet's atmosphere

Modern computer graphics is mostly polygonal. 3D models are represented as a set of polygons that form a mesh, which then gets textured and lit. In effect, rendering a 3D object means rendering its surface. That works fine for objects light can't pass through. But what about materials that do let light through? A good example is wax: light from a candle flame can pass through wax and light it up from the inside. This effect is called subsurface scattering.

A planet's atmosphere isn't transparent either — as light travels through this non-transparent medium, it collides with microscopic particles and aerosols (more on that below), changing along its path from the sun to the observer. The thickness of the atmosphere is defined by the Kármán line — an altitude of 100 km above sea level. This altitude is considered the upper boundary of the atmosphere and the line between Earth's atmosphere and space.

Existing approaches

As of this writing, there are two established approaches to computing atmospheric scattering:

  • The Nishita approach, described in two papers: "Display of the Earth Taking into Account Atmospheric Scattering" (1993) and "Display of the Earth Taking into Account Atmospheric Scattering" (1996)

  • The Preetham approach, described in "A Practical Analytic Model for Daylight" (1999)

In this article we'll be working with Nishita's atmosphere model. It's worth noting that the algorithms above haven't changed much since they were first proposed and are still in use today. What differs is the implementation: there are now plenty of ways to speed up these fairly computationally demanding algorithms.

The atmosphere model

As we know, a planet's atmosphere is made up of particles. When a ray of light (really an electromagnetic wave) collides with one of these particles, it gets deflected from its original direction. This can happen many times over, and that process is exactly what's called atmospheric scattering — the scattering of light within a planet's atmosphere.

As mentioned above, the atmosphere is about 100 km thick. The first thing to account for is that atmospheric density varies with altitude. Most models treat this density as changing exponentially:

density(h)=density(0)ehHdensity(h) = density(0) e^{-{h \over H}}

In the formula above, density(0) is the atmospheric density at sea level, H is the thickness of the atmosphere, and h is the altitude at which we're computing the density.

The atmosphere model then introduces the particles the atmosphere is made of, plus aerosols — larger particles found only in the lower layers of the atmosphere.

Light scattering caused by collisions with small particles (present throughout the whole thickness of the atmosphere) is called Rayleigh scattering. Light scattering caused by collisions with aerosols is called Mie scattering. Nishita's atmosphere model is essentially built up from these two kinds of scattering combined.

Rayleigh scattering

As mentioned above, Rayleigh scattering is light scattering that happens when light collides with the particles that make up the atmosphere. The fraction of energy lost in a single collision is called the Rayleigh scattering coefficient (or the extinction coefficient), and it's computed with the following formula:

βR(λ,h)=8π3(n21)23Nλ4ehHR\beta_R(\lambda, h) = {\frac{8\pi^3(n^2 - 1)^2}{3N\lambda^4}}e^{-{h \over H_R}}

In the formula above:

  • λ – wavelength
  • h – altitude above sea level
  • n – the refractive index of air (1.00029)
  • N – the number of molecules per cubic meter of the standard atmosphere (2.504 * 1025)
  • HR – the scale height (usually taken to be around 8–9 km)

Note that wavelength sits in the denominator of the formula above, meaning the longer the wavelength, the less energy is lost in a collision with an atmospheric particle. Take the following wavelengths: 440nm, 550nm, 680nm — the peak values for blue, green, and red respectively.

So the blue component scatters far more than the red one, which is especially visible when light waves travel a long path through the atmosphere: at sunset. That's exactly what accounts for the orange-red colors of the sky at sunset.

To speed up the calculations, instead of the whole visible spectrum we'll only use these three peak wavelengths (440nm, 550nm, and 680nm), and for altitude we can just use sea level. That makes it possible to precompute the Rayleigh scattering coefficients for the RGB components and use them in the shader as constants, giving sky colors close to the real thing without sacrificing the algorithm's speed.

Next we introduce the phase function. It describes how the scattering direction relates to the fraction of light lost in that direction. If we denote the scattering angle as θ, the phase function for Rayleigh scattering looks like this:

PR(μ)=316π(1+μ2)P_R(\mu) = \frac{3}{16\pi}(1 + \mu^2)

where:

μ=cos(θ)\mu = cos(\theta)

Combining the phase function with the scattering coefficient gives us the final Rayleigh scattering equation, which describes the fraction of light with wavelength λ at altitude h that gets scattered in direction θ:

S(λ,θ,h)=βR(λ,h)PR(μ)S(\lambda, \theta, h) = \beta_R(\lambda, h)P_R(\mu)

Mie scattering

In the lower layers of the atmosphere we also need to account for so-called aerosols (particles larger than the wavelength of light, like smog or dust), not just the particles the atmosphere itself is made of. The calculation follows the same approach as Rayleigh scattering — only the formulas for the scattering coefficient and the phase function change. The Mie scattering coefficient is computed with the following formula:

βM(λ,h)=βM(λ,0)ehHM\beta_M(\lambda, h) = \beta_M(\lambda, 0)e^{-{h \over H_M}}

In the formula above:

  • λ – wavelength
  • h – altitude above sea level
  • HM – the scale height (for Mie scattering, usually taken to be 1.2 km)
  • β(λ,0) – the precomputed scattering coefficient measured at sea level (21e-6)

The phase function for Mie scattering looks like this:

PM(μ)=38π(1g2)(1+μ2)(2+g2)(1+g22μg)32P_M(\mu) = \frac{3}{8\pi} \frac{(1 - g^2)(1 + \mu^2)}{(2 + g^2)(1 + g^2 - 2 \mu g)^{\frac{3}{2}}}

Note that a new variable shows up here — g. It's called the anisotropy coefficient, and for Earth's atmosphere its value is usually taken to be 0.76.

Computer graphicsshadingatmospheric-scatteringrayleigh-scatteringmie-scattering
Karen Grigorian
Karen Grigorian