GLSL Atmospheric Ozone Absorption Formula

This article explains how to compute atmospheric ozone absorption across standard RGB sunlight spectrum channels using GLSL. It covers the underlying Beer-Lambert extinction formula, the Chappuis band absorption coefficients for visual wavelengths, the stratospheric tent function used to approximate ozone density by altitude, and a ready-to-use GLSL shader implementation.

The Physics of Ozone Absorption

Ozone absorbs visible light primarily within the Chappuis band (roughly 400 nm to 750 nm), with peak absorption occurring in the green and yellow spectrum around 600 nm. Because ozone preferentially absorbs yellow and orange wavelengths while letting blue light pass, it is largely responsible for the deep blue appearance of the sky during civil and nautical twilight.

Light attenuation through atmospheric ozone is modeled using the Beer-Lambert Law:

\[T(\lambda) = \exp\left(-\beta_{\text{ozone}}(\lambda) \cdot \tau_{\text{ozone}}\right)\]

Where:

  • \(T(\lambda)\) is the spectral transmittance.
  • \(\beta_{\text{ozone}}(\lambda)\) is the wavelength-dependent extinction cross-section.
  • \(\tau_{\text{ozone}}\) is the integrated optical depth along the light ray.

Optical Coefficients for Sunlight Channels

For real-time physically based rendering in RGB color space (typically sampled around \(650\text{ nm}\) for Red, \(550\text{ nm}\) for Green, and \(440\text{ nm}\) for Blue), the ozone extinction coefficients per meter are approximately:

\[\beta_{\text{ozone}} = (0.650 \times 10^{-6},\; 1.881 \times 10^{-6},\; 0.085 \times 10^{-6})\text{ m}^{-1}\]

In GLSL vector format:

const vec3 OZONE_EXTINCTION = vec3(0.650e-6, 1.881e-6, 0.085e-6); // 1/m

Ozone Density Altitude Profile

Unlike Rayleigh and Mie scattering, which decay exponentially from the surface, ozone concentrates primarily in the stratosphere between 15 km and 35 km, peaking at approximately 25 km. A standard triangular tent profile models this distribution:

\[\rho_{\text{ozone}}(h) = \max\left(0.0, 1.0 - \frac{|h - h_0|}{w}\right)\]

Where:

  • \(h\) is the current altitude above the planet surface (in meters).
  • \(h_0\) is the peak layer center altitude (\(25{,}000\text{ m}\)).
  • \(w\) is the layer half-width (\(15{,}000\text{ m}\)).

GLSL Implementation

The following GLSL functions calculate the local ozone density and evaluate the integrated ozone transmittance along a ray.

// Extinction coefficients for RGB sunlight channels (1/meters)
const vec3 OZONE_EXTINCTION = vec3(0.650e-6, 1.881e-6, 0.085e-6);

// Parameters for the ozone density profile (meters)
const float OZONE_CENTER_ALTITUDE = 25000.0;
const float OZONE_WIDTH = 15000.0;

// Computes relative ozone density at a given altitude
float getOzoneDensity(float altitude) {
    return max(0.0, 1.0 - abs(altitude - OZONE_CENTER_ALTITUDE) / OZONE_WIDTH);
}

// Computes optical depth across a ray segment
float integrateOzoneOpticalDepth(vec3 rayStart, vec3 rayDir, float rayLength, float planetRadius, int sampleCount) {
    float stepSize = rayLength / float(sampleCount);
    float accumulatedDepth = 0.0;
    
    for (int i = 0; i < sampleCount; ++i) {
        vec3 samplePoint = rayStart + rayDir * ((float(i) + 0.5) * stepSize);
        float altitude = length(samplePoint) - planetRadius;
        accumulatedDepth += getOzoneDensity(altitude) * stepSize;
    }
    
    return accumulatedDepth;
}

// Computes ozone spectral transmittance across RGB channels
vec3 calculateOzoneTransmittance(vec3 rayStart, vec3 rayDir, float rayLength, float planetRadius) {
    const int SAMPLES = 16;
    float opticalDepth = integrateOzoneOpticalDepth(rayStart, rayDir, rayLength, planetRadius, SAMPLES);
    
    // Beer-Lambert law applied per channel
    return exp(-OZONE_EXTINCTION * opticalDepth);
}

Usage Notes

To evaluate solar attenuation, set rayDir toward the sun from the view position to the top of the atmosphere. Multiply the returned RGB transmittance vector by the incoming extraterrestrial sunlight irradiance before combining with Rayleigh and Mie in-scattering terms.