MIT License NuGet

Home / Features / Sky and atmosphere

Sky, atmosphere and weather

The sky is computed, not textured. Scattering LUTs feed a full day and night cycle: sun and moon positions, lunar phase, sky colour, ambient irradiance and aerial perspective all derive from one phase value.

What the atmosphere pass produces

SkyAtmosphereEffect runs in the FrameStart compute phase and publishes five textures. Everything downstream — the sky itself, fog over distant geometry, ambient light on your models — samples those, which is why they cannot drift out of agreement.

  • Transmittance LUT — how much light survives a path through the air.
  • Multiple-scattering LUT — the second-order term that makes a blue sky blue rather than black with a bright band.
  • Sky-view LUT — the radiance of the sky in every direction, at 256×128 by default.
  • Cloud noise — a 512×512 noise texture the cloud layers sample.
  • Aerial-perspective LUT — a 3D volume of in-scattering against distance.

Types to read: Rendering/Atmosphere.cs, DayNightCycle.cs, SkyState.cs, Effects/SkyAtmosphere.cs.

Procedural sky at sunrise over the sea Sky atmosphere
Sunrise over the sea in the reference application.

A real planet, in kilometres

The atmosphere is parameterised physically rather than artistically. Defaults describe Earth: a 6360 km ground radius, a 6460 km atmosphere shell, a Rayleigh scale height of 8 km, and a viewer 200 m above the ground.

Field on AtmosphereDefaultMeaning
GroundRadiusKm6360Planet radius. Shrink it and the horizon curves visibly.
AtmosphereRadiusKm6460Top of the atmosphere shell.
ViewAltitudeKm0.2Camera altitude fed to the LUTs.
RayleighHeightKm8Exponential scale height for molecular scattering.
MiePhaseG0.8Forward-scattering anisotropy for aerosols — the glow around the sun.
GroundAlbedo0.1How much light bounces back up into the sky.
MultiScatterGain1.0Scales the multiple-scattering term. Below 1 gives a harsher, thinner sky.

Atmosphere is a static class, and that is a deliberate narrowing too: there is one sky per application, not one per camera or per scene. It keeps the LUTs to a single set.

Sun, moon and stars

Both bodies are real discs with real angular sizes, which is what makes their shadows and their specular highlights the right size without tuning.

FieldDefaultMeaning
SunIrradiance12Sun brightness in engine units.
SunAngularRadiusDeg0.2665The sun's real angular radius as seen from Earth.
SunDiskRadiance30Radiance of the disc itself, separate from its lighting contribution.
MoonIrradiance0.6Moonlight contribution.
MoonAngularRadiusDeg0.259The moon's real angular radius.
MoonColor(0.55, 0.68, 1.0)Cool cast, because moonlight reads blue to a dark-adapted eye.
StarRadiance0.15Star brightness.
StarVisibilityTwilightDeg18Sun depression angle at which stars are fully out — astronomical twilight.
StarRotation, StarPoleAxisWhere the sky rotates about, if you want a different latitude or a different planet.
NightAirglow0.004Faint emission that keeps a moonless night from being pure black.

The day and night cycle

DayNightCycle turns one phase value into everything that depends on time of day. Evaluate is the entry point; the rest of the class is the conversions you need around it.

// A day takes 100 seconds at the default speed of 0.01.
WorldSettings.DefaultDayNightSpeed = 0.004f;   // slower
WorldSettings.DefaultStartHour = 5.5f;         // just before sunrise

// Anywhere afterwards:
float phase = DayNightCycle.PhaseFromHour(18f); // dusk
float hour = DayNightCycle.HourFromPhase(phase);
MemberWhat it gives you
EvaluateDrives sun and moon direction, tint and ambient for a phase.
BodyPositionDirection to the sun or moon at a phase.
MoonPhaseFactorLunar illumination, from a SynodicDays cycle — the moon waxes and wanes over real months.
SkyTint, AmbientScaleColour cast and ambient strength through the day.
StarAngleRotation of the star field.
SunriseHourWhen the sun crosses the horizon, for scheduling anything against it.
CelestialPoleThe axis the sky turns about.

Speed and start hour live on WorldSettings, which reads from the application's settings object and therefore survives a restart if you persist settings.

Weather: four presets and a lerp

SkyState is a struct holding cloud layers plus the handful of scalars that make clouds read as weather rather than as texture. Four presets ship, and Lerp between them is how a front rolls in.

// Hold a settled state:
Atmosphere.Clouds = SkyState.Overcast;

// Or move between two over a minute:
float t = MathF.Min(1f, elapsed / 60f);
Atmosphere.Clouds = SkyState.Lerp(SkyState.Fair, SkyState.Storm, t);
FieldMeaning
Layers, LayerCountUp to a few SkyCloudLayer entries, each with its own altitude and wind.
AlbedoHow bright the cloud material is.
ShadowStrengthHow much the cloud deck dims the sun below it.
PhaseGForward scattering within the cloud — the silver lining.
AmbientFloorMinimum ambient under heavy cover, so an overcast scene does not go flat black.
ForwardGainExtra gain on light scattered towards the viewer.

Each layer is a SkyCloudLayer: AltitudeKm, ThicknessKm, TileKm, Coverage, Density, Detail and WindKmPerSec. Wind accumulates into Atmosphere.CloudWindOffsetKm, so clouds drift without any per-frame work from you.

Aerial perspective

Distant geometry picks up the colour of the air in front of it, sampled from the aerial LUT. This is the single cheapest thing you can enable to make a scene feel large.

SettingDefaultMeaning
SkyProceduralSky mode; read at initialization.
SkyViewLutWidth / Height256 / 128Sky-view LUT resolution.
SkyRayMarchSteps16Steps per LUT ray. The main sky quality/cost dial.
CloudNoiseSize512Cloud noise texture edge.
AerialPerspectiveonWhether the LUT is built and applied.
AerialMaxDistanceKm32Distance the LUT covers. Beyond it, the far value is held.
AerialIntensity1.0Lerp weight: 1 is physical, higher exaggerates it.

AerialIntensity above 1 is not a bug fix, it is a concession to scale. A scene 200 m across gets almost no physical in-scattering; if you want it to read as a landscape anyway, exaggerate the weight and accept that it is a lie.

Known gaps

  • Partial Volumetric clouds. Cloud layers are shaded from a noise texture against a layer model, not ray-marched as a volume. They read well from the ground and do not survive flying through them.
  • Absent Precipitation, wind on foliage, wet surfaces. Weather affects light and cloud cover, not the ground.
  • Absent Volumetric fog and light shafts. Aerial perspective is per-pixel in-scattering, not a participating medium the sun can shaft through.