Home
Shaders and presets

Sky & Atmosphere Shaders

GLSL shaders for procedural sky with atmospheric scattering

Sky & Atmosphere Shaders

Physically-based atmospheric scattering shaders for procedural sky rendering with Rayleigh and Mie scattering.

Available Shaders

import {
  skyVertexShader,
  skyFragmentShader,
  atmosphereVertexShader,
  atmosphereFragmentShader,
} from 'strata-game-library/shaders';

Sky Shader

Complete procedural sky with sun and atmospheric effects:

Uniforms

UniformTypeDescription
sunPositionvec3Sun position in world space
turbidityfloatAtmospheric haziness (2-20)
rayleighfloatBlue scattering coefficient
mieCoefficientfloatSun halo coefficient
mieDirectionalGfloatHalo directionality (0-1)
sunIntensityfloatSun brightness

Usage

import { skyVertexShader, skyFragmentShader } from 'strata-game-library/shaders';

const skyMaterial = new THREE.ShaderMaterial({
  vertexShader: skyVertexShader,
  fragmentShader: skyFragmentShader,
  uniforms: {
    sunPosition: { value: new THREE.Vector3(100, 50, 100) },
    turbidity: { value: 10 },
    rayleigh: { value: 2 },
    mieCoefficient: { value: 0.005 },
    mieDirectionalG: { value: 0.8 },
    sunIntensity: { value: 1.0 },
  },
  side: THREE.BackSide,
});

const sky = new THREE.Mesh(
  new THREE.SphereGeometry(5000, 32, 32),
  skyMaterial
);

Atmosphere Shader

Standalone atmospheric scattering for planet rendering:

Uniforms

UniformTypeDescription
uSunDirectionvec3Normalized sun direction
uAtmosphereRadiusfloatOuter atmosphere radius
uPlanetRadiusfloatPlanet surface radius
uRayleighScatteringvec3RGB scattering coefficients
uMieScatteringfloatMie scattering coefficient
uRayleighScaleHeightfloatRayleigh density falloff
uMieScaleHeightfloatMie density falloff

Usage

import { atmosphereVertexShader, atmosphereFragmentShader } from 'strata-game-library/shaders';

const atmosphereMaterial = new THREE.ShaderMaterial({
  vertexShader: atmosphereVertexShader,
  fragmentShader: atmosphereFragmentShader,
  uniforms: {
    uSunDirection: { value: new THREE.Vector3(0, 1, 0).normalize() },
    uAtmosphereRadius: { value: 6420000 },
    uPlanetRadius: { value: 6360000 },
    uRayleighScattering: { value: new THREE.Vector3(5.5e-6, 13.0e-6, 22.4e-6) },
    uMieScattering: { value: 21e-6 },
    uRayleighScaleHeight: { value: 8000 },
    uMieScaleHeight: { value: 1200 },
  },
  side: THREE.BackSide,
  transparent: true,
});

GLSL Code Samples

Rayleigh Scattering

vec3 rayleighScattering(float cosTheta, vec3 lambda) {
  // Rayleigh scattering coefficient
  vec3 beta = (8.0 * pow(PI, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0)) /
              (3.0 * N * pow(lambda, vec3(4.0)));

  // Phase function
  float phase = (3.0 / 16.0 * PI) * (1.0 + cosTheta * cosTheta);

  return beta * phase;
}

Mie Scattering

float miePhase(float cosTheta, float g) {
  float g2 = g * g;
  return (3.0 / (8.0 * PI)) *
         ((1.0 - g2) * (1.0 + cosTheta * cosTheta)) /
         (pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5) * (2.0 + g2));
}

Atmospheric Density

float atmosphericDensity(float altitude, float scaleHeight) {
  return exp(-altitude / scaleHeight);
}

Ray-Sphere Intersection

vec2 raySphereIntersect(vec3 rayOrigin, vec3 rayDir, float sphereRadius) {
  float a = dot(rayDir, rayDir);
  float b = 2.0 * dot(rayOrigin, rayDir);
  float c = dot(rayOrigin, rayOrigin) - sphereRadius * sphereRadius;
  float d = b * b - 4.0 * a * c;

  if (d < 0.0) return vec2(-1.0);

  return vec2(
    (-b - sqrt(d)) / (2.0 * a),
    (-b + sqrt(d)) / (2.0 * a)
  );
}

Time of Day Presets

// Dawn
uniforms.sunPosition.value.set(100, 5, 0);
uniforms.turbidity.value = 4;
uniforms.rayleigh.value = 2;

// Noon
uniforms.sunPosition.value.set(0, 100, 0);
uniforms.turbidity.value = 10;
uniforms.rayleigh.value = 1;

// Sunset
uniforms.sunPosition.value.set(-100, 5, 0);
uniforms.turbidity.value = 5;
uniforms.rayleigh.value = 3;

// Night
uniforms.sunPosition.value.set(0, -100, 0);
uniforms.turbidity.value = 2;
uniforms.rayleigh.value = 0.1;