Variable ATMOSPHERE_GLSLConst
ATMOSPHERE_GLSL: "\n uniform float uAtmoEnabled;\n uniform vec3 uAtmoColor;\n uniform float uAtmoNear;\n uniform float uAtmoFar;\n uniform float uAtmoDensity;\n\n /** Haze fraction 0–1 at a world-XZ point: 0 = untouched, 1 = pure atmosphere. */\n float atmosphereFactor(vec2 worldXZ) {\n if (uAtmoEnabled < 0.5) return 0.0;\n float d = distance(worldXZ, cameraPosition.xz);\n return smoothstep(uAtmoNear, uAtmoFar, d) * uAtmoDensity;\n }\n\n vec3 applyAtmosphere(vec3 color, vec2 worldXZ) {\n return mix(color, uAtmoColor, atmosphereFactor(worldXZ));\n }\n" = ...
Shared aerial-perspective GLSL: every surface material (terrain, roads, all six liquid layers) mixes its final color toward a single atmosphere color as it recedes, so the far edge of the map dissolves into the sky instead of ending against a hard void.
Distance is measured on the ground plane (world XZ), not from the eye. With a pitched RTS camera the far map edge is exactly what should dissolve, and a peak on the horizon then hazes as much as the valley beside it — eye-distance fog would leave ridgelines cut out against the sky. Because every material uses the same measure, terrain, roads, and water fade in step with no seam at a shoreline.
cameraPositionis declared by three.js in both GLSL1 and GLSL3 fragment shaders, so this block drops into either without changes.