atmosphere: add physical Rayleigh sky scattering

This commit is contained in:
Richard Zink committed 2026-10-12 15:08:59 +02:00
1 parent 629b1b6ab2
commit 7329957658
2 files changed
+35 -1

No files matched your search

+2
View File
@@ -313,6 +313,8 @@ window.CONFIG = {
albedoGain: 1.0, // theme share on surface colours
skyGain: 0.45, // diffuse skylight share on surfaces
airGain: 0.55, // Rayleigh airlight strength (blue-biased)
physicalSky: true, // Rayleigh sky scattering instead of pure theme gradient
rayleighGain: 8.0, // exposure for the physical sky term
distanceFog: false, // legacy aerial perspective is off
model: {
enabled: false // volumetric atmosphere/fog removed
+33 -1
View File
@@ -105,6 +105,10 @@ var FRAG_SRC = [
'uniform float uStarAmb;', // diffuse starlight + airglow
'uniform float uPhysical;',
'uniform vec3 uAirColor;', // Rayleigh airlight at the horizon
'uniform vec3 uRayleighBeta;', // vertical Rayleigh optical depth RGB
'uniform float uSunAirMass;', // relative air mass of the sun beam
'uniform float uRayleighGain;',
'uniform float uPhysicalSkyOn;',
'uniform vec3 uCloudAlbedo;', // theme-tinted but brightness-normalised
'uniform float uAirDensity;', // slant optical depth per world unit
'uniform float uCloudHaze;', // clouds sit above most of the haze: much weaker
@@ -336,6 +340,21 @@ var FRAG_SRC = [
// distance fog saturates to, so no seam at the silhouette.
'float skyT = clamp(rd.y * 0.7 + 0.5, 0.5, 1.0);',
'vec3 col = mix(uBg, uSky, skyT);',
'if (uPhysicalSkyOn > 0.5) {',
'float cosT = dot(rd, uSunDir);',
'float phase = 0.5 + 0.5 * cosT * cosT;',
'float sunUp = smoothstep(-0.25, 0.05, uSunAlt);',
'vec3 sunTop = uSunColor * uSunInt * sunUp;',
'float viewY = max(rd.y, 0.0);',
'float mView = (viewY > 0.02) ? min(38.0, 1.0 / viewY) : 38.0;',
'vec3 tauView = uRayleighBeta * mView;',
'vec3 single = phase * sunTop * (1.0 - exp(-tauView));',
'vec3 multi = phase * sunTop * tauView * tauView * 0.12;',
'vec3 ambient = max(vec3(uSkyAmb), uStarAmb * vec3(0.7, 0.85, 1.0)) *',
'(1.0 - exp(-tauView)) * vec3(0.35, 0.55, 1.0);',
'vec3 phys = (single + multi + ambient) * uRayleighGain;',
'col = mix(col, phys, 0.82);',
'}',
'float nightFactor = 1.0 - smoothstep(-0.15, 0.05, uSunAlt);',
'float skyMask = smoothstep(-0.20, 0.40, rd.y);',
// Stars must not sit on the moon: the disc is opaque, so every
@@ -825,6 +844,10 @@ function init(canvas) {
var uStarAmb = gl.getUniformLocation(prog, 'uStarAmb');
var uPhysical = gl.getUniformLocation(prog, 'uPhysical');
var uAirColor = gl.getUniformLocation(prog, 'uAirColor');
var uRayleighBeta = gl.getUniformLocation(prog, 'uRayleighBeta');
var uSunAirMass = gl.getUniformLocation(prog, 'uSunAirMass');
var uRayleighGain = gl.getUniformLocation(prog, 'uRayleighGain');
var uPhysicalSkyOn = gl.getUniformLocation(prog, 'uPhysicalSkyOn');
var uCloudAlbedo = gl.getUniformLocation(prog, 'uCloudAlbedo');
var uAirDensity = gl.getUniformLocation(prog, 'uAirDensity');
var uCloudHaze = gl.getUniformLocation(prog, 'uCloudHaze');
@@ -921,7 +944,9 @@ function init(canvas) {
uAtmoBlueColor: uAtmoBlueColor, uAtmoGrayColor: uAtmoGrayColor,
uSunColor: uSunColor, uSunInt: uSunInt, uMoonColor: uMoonColor,
uMoonInt: uMoonInt, uSkyAmb: uSkyAmb, uStarAmb: uStarAmb,
uPhysical: uPhysical, uAirColor: uAirColor, uCloudAlbedo: uCloudAlbedo,
uPhysical: uPhysical, uAirColor: uAirColor,
uRayleighBeta: uRayleighBeta, uSunAirMass: uSunAirMass,
uRayleighGain: uRayleighGain, uPhysicalSkyOn: uPhysicalSkyOn, uCloudAlbedo: uCloudAlbedo,
uAirDensity: uAirDensity, uCloudHaze: uCloudHaze,
uSkyTex: uSkyTex, uSkyOn: uSkyOn, uStarLon: uStarLon, uPole: uPole,
uMoonTex: uMoonTex, uMoonTexOn: uMoonTexOn, uMoonR: uMoonR,
@@ -2337,6 +2362,9 @@ var MOON_TEX_SRC = (typeof window.__moonTex === 'string' && window.__moonTex)
var ATMO_NIGHT_FLOOR = (typeof ATMO.nightFloor === 'number') ? Math.max(0.01, ATMO.nightFloor) : 0.05;
var ATMO_ALBEDO_GAIN = (typeof ATMO.albedoGain === 'number') ? Math.max(0.1, ATMO.albedoGain) : 1.0;
var ATMO_SKY_GAIN = (typeof ATMO.skyGain === 'number') ? Math.max(0.05, ATMO.skyGain) : 0.55;
var ATMO_PHYSICAL_SKY = ATMO.physicalSky !== false;
var ATMO_RAYLEIGH_GAIN = (typeof ATMO.rayleighGain === 'number')
? Math.max(0.1, Math.min(30.0, ATMO.rayleighGain)) : 8.0;
// ---- Artificial light switching (CONFIG.lights) -------------------------
// Every individual light owns a sun-altitude threshold inside the window
@@ -5457,6 +5485,10 @@ window.clouds3dRender = function(target) {
_amb *= _exp;
}
gl.uniform3f(s.uAirColor, _air[0], _air[1], _air[2]);
gl.uniform3f(s.uRayleighBeta, TAU_RAYLEIGH[0], TAU_RAYLEIGH[1], TAU_RAYLEIGH[2]);
gl.uniform1f(s.uSunAirMass, airMass(Math.max(sunAlt, 0.0)));
gl.uniform1f(s.uRayleighGain, ATMO_RAYLEIGH_GAIN);
gl.uniform1f(s.uPhysicalSkyOn, ATMO_PHYSICAL_SKY ? 1.0 : 0.0);
gl.uniform3f(s.uSunColor, _beam[0], _beam[1], _beam[2]);
gl.uniform1f(s.uSunInt, _beamL);
gl.uniform3f(s.uMoonColor, _mBeam[0], _mBeam[1], _mBeam[2]);