atmosphere: add initial volumetric atmosphere shell
This commit is contained in:
1 parent
1f925c6f68
commit
b9094ebd8b
2 files changed
+113
-1
No files matched your search
@@ -305,6 +305,15 @@ window.CONFIG = {
|
|||||||
albedoGain: 1.0, // theme share on surface colours
|
albedoGain: 1.0, // theme share on surface colours
|
||||||
skyGain: 0.45, // diffuse skylight share on surfaces
|
skyGain: 0.45, // diffuse skylight share on surfaces
|
||||||
airGain: 0.55, // Rayleigh airlight strength (blue-biased)
|
airGain: 0.55, // Rayleigh airlight strength (blue-biased)
|
||||||
|
distanceFog: false, // legacy aerial perspective is off
|
||||||
|
model: {
|
||||||
|
enabled: true,
|
||||||
|
heightKm: 35.0, // full atmosphere shell around the planet
|
||||||
|
scaleHeightKm: 8.5, // density falls exponentially with altitude
|
||||||
|
density: 0.12, // base optical density
|
||||||
|
grayTau: 1.5, // high optical depth becomes grey fog
|
||||||
|
gain: 2.0 // scattering brightness
|
||||||
|
},
|
||||||
hazeResidual: 0.30, // surface colour surviving at the full fog distance
|
hazeResidual: 0.30, // surface colour surviving at the full fog distance
|
||||||
cloudBrightness: 1.0, // cloud albedo (theme hue, brightness from the model)
|
cloudBrightness: 1.0, // cloud albedo (theme hue, brightness from the model)
|
||||||
cloudHaze: 0.22, // share of the ground haze applied to the deck
|
cloudHaze: 0.22, // share of the ground haze applied to the deck
|
||||||
|
|||||||
Vendored
+104
-1
@@ -85,7 +85,15 @@ var FRAG_SRC = [
|
|||||||
'uniform float uSkyOn;', // 0 until the star texture is built
|
'uniform float uSkyOn;', // 0 until the star texture is built
|
||||||
'uniform float uStarLon;', // sidereal rotation offset (radians)
|
'uniform float uStarLon;', // sidereal rotation offset (radians)
|
||||||
'uniform vec3 uPole;', // north celestial pole in world coords
|
'uniform vec3 uPole;', // north celestial pole in world coords
|
||||||
'uniform int uMode;', // 0 = sky+stars, 1 = clouds (transparent over mesh)
|
'uniform int uMode;', // 0 = sky+stars, 1 = clouds, 2 = atmosphere shell
|
||||||
|
'uniform float uAtmoModelOn;',
|
||||||
|
'uniform float uAtmoHeightUnits;',
|
||||||
|
'uniform float uAtmoScaleHeightUnits;',
|
||||||
|
'uniform float uAtmoDensity;',
|
||||||
|
'uniform float uAtmoGrayTau;',
|
||||||
|
'uniform float uAtmoGain;',
|
||||||
|
'uniform vec3 uAtmoBlueColor;',
|
||||||
|
'uniform vec3 uAtmoGrayColor;',
|
||||||
'uniform vec3 uSunColor;', // direct beam after atmospheric extinction
|
'uniform vec3 uSunColor;', // direct beam after atmospheric extinction
|
||||||
'uniform float uSunInt;',
|
'uniform float uSunInt;',
|
||||||
'uniform vec3 uMoonColor;',
|
'uniform vec3 uMoonColor;',
|
||||||
@@ -227,6 +235,64 @@ var FRAG_SRC = [
|
|||||||
'vec3 ro = nearH.xyz / nearH.w;',
|
'vec3 ro = nearH.xyz / nearH.w;',
|
||||||
'vec3 rd = normalize(farH.xyz / farH.w - ro);',
|
'vec3 rd = normalize(farH.xyz / farH.w - ro);',
|
||||||
|
|
||||||
|
'if (uMode == 2) {',
|
||||||
|
'if (uAtmoModelOn < 0.5) { gl_FragColor = vec4(0.0); return; }',
|
||||||
|
'float R = max(1.0, uEarthRadius);',
|
||||||
|
'float H = max(0.1, uAtmoHeightUnits);',
|
||||||
|
'float Hs = max(0.01, uAtmoScaleHeightUnits);',
|
||||||
|
'vec3 C = vec3(ro.x, -R, ro.z);',
|
||||||
|
'vec3 oc = ro - C;',
|
||||||
|
'float b = dot(oc, rd);',
|
||||||
|
'float rOut = R + H;',
|
||||||
|
'float cOut = dot(oc, oc) - rOut * rOut;',
|
||||||
|
'float discOut = b * b - cOut;',
|
||||||
|
'float tStart = 0.0;',
|
||||||
|
'float tEnd = 100.0;',
|
||||||
|
'if (discOut > 0.0) {',
|
||||||
|
'float sq = sqrt(discOut);',
|
||||||
|
'float t1 = -b - sq;',
|
||||||
|
'float t2 = -b + sq;',
|
||||||
|
'if (dot(oc, oc) > rOut * rOut) tStart = max(0.0, t1);',
|
||||||
|
'tEnd = max(0.0, t2);',
|
||||||
|
'}',
|
||||||
|
'float cIn = dot(oc, oc) - R * R;',
|
||||||
|
'float discIn = b * b - cIn;',
|
||||||
|
'float tInner = 100000.0;',
|
||||||
|
'if (discIn > 0.0) {',
|
||||||
|
'float sq = sqrt(discIn);',
|
||||||
|
'float t1 = -b - sq;',
|
||||||
|
'float t2 = -b + sq;',
|
||||||
|
'if (t1 > 0.0) tInner = t1;',
|
||||||
|
'else if (t2 > 0.0) tInner = t2;',
|
||||||
|
'}',
|
||||||
|
'if (tInner < 100000.0) tEnd = min(tEnd, tInner);',
|
||||||
|
'if (tEnd <= tStart) { gl_FragColor = vec4(0.0); return; }',
|
||||||
|
'float step = (tEnd - tStart) / 32.0;',
|
||||||
|
'float t = tStart + step * 0.5;',
|
||||||
|
'float tau = 0.0;',
|
||||||
|
'vec3 scatter = vec3(0.0);',
|
||||||
|
'float cosTA = dot(rd, uSunDir);',
|
||||||
|
'float cosTM = dot(rd, uMoonDir);',
|
||||||
|
'float sunPhase = 0.25 + 0.75 * pow(max(0.0, cosTA), 2.0);',
|
||||||
|
'float moonPhase = 0.25 + 0.75 * pow(max(0.0, cosTM), 2.0);',
|
||||||
|
'for (int i = 0; i < 32; i++) {',
|
||||||
|
'vec3 p = ro + rd * t;',
|
||||||
|
'float alt = max(0.0, length(p - C) - R);',
|
||||||
|
'float dens = exp(-alt / Hs);',
|
||||||
|
'float dtau = uAtmoDensity * dens * step;',
|
||||||
|
'float transBefore = exp(-tau);',
|
||||||
|
'float grayMix = clamp(tau / max(0.01, uAtmoGrayTau), 0.0, 1.0);',
|
||||||
|
'vec3 atmoCol = mix(uAtmoBlueColor, uAtmoGrayColor, grayMix);',
|
||||||
|
'vec3 light = uSunColor * uSunInt * sunPhase + uMoonColor * uMoonInt * moonPhase * 2.0 + max(vec3(uSkyAmb), uStarAmb * vec3(0.7, 0.85, 1.0)) * 0.65;',
|
||||||
|
'scatter += atmoCol * light * dtau * transBefore;',
|
||||||
|
'tau += dtau;',
|
||||||
|
't += step;',
|
||||||
|
'}',
|
||||||
|
'float alpha = clamp(1.0 - exp(-tau), 0.0, 1.0);',
|
||||||
|
'vec3 col = scatter / max(alpha, 1e-4) * uAtmoGain;',
|
||||||
|
'gl_FragColor = vec4(col, alpha);',
|
||||||
|
'return;',
|
||||||
|
'}',
|
||||||
'if (uMode == 0) {',
|
'if (uMode == 0) {',
|
||||||
// skyT floor at 0.5: at and below the horizon the sky keeps
|
// skyT floor at 0.5: at and below the horizon the sky keeps
|
||||||
// the exact horizon colour - the same value the terrain's
|
// the exact horizon colour - the same value the terrain's
|
||||||
@@ -853,6 +919,11 @@ function init(canvas) {
|
|||||||
uCloudTop: uCloudTop, uCloudBot: uCloudBot,
|
uCloudTop: uCloudTop, uCloudBot: uCloudBot,
|
||||||
uElev: uElev, uElevOn: uElevOn, uElevScale: uElevScale,
|
uElev: uElev, uElevOn: uElevOn, uElevScale: uElevScale,
|
||||||
uSunDir: uSunDir, uMoonDir: uMoonDir, uMode: uMode,
|
uSunDir: uSunDir, uMoonDir: uMoonDir, uMode: uMode,
|
||||||
|
uAtmoModelOn: uAtmoModelOn, uAtmoHeightUnits: uAtmoHeightUnits,
|
||||||
|
uAtmoScaleHeightUnits: uAtmoScaleHeightUnits, uAtmoDensity: uAtmoDensity,
|
||||||
|
uAtmoGrayTau: uAtmoGrayTau, uAtmoGain: uAtmoGain,
|
||||||
|
uEarthRadius: uEarthRadius,
|
||||||
|
uAtmoBlueColor: uAtmoBlueColor, uAtmoGrayColor: uAtmoGrayColor,
|
||||||
uSunColor: uSunColor, uSunInt: uSunInt, uMoonColor: uMoonColor,
|
uSunColor: uSunColor, uSunInt: uSunInt, uMoonColor: uMoonColor,
|
||||||
uMoonInt: uMoonInt, uSkyAmb: uSkyAmb, uStarAmb: uStarAmb,
|
uMoonInt: uMoonInt, uSkyAmb: uSkyAmb, uStarAmb: uStarAmb,
|
||||||
uPhysical: uPhysical, uAirColor: uAirColor, uCloudAlbedo: uCloudAlbedo,
|
uPhysical: uPhysical, uAirColor: uAirColor, uCloudAlbedo: uCloudAlbedo,
|
||||||
@@ -2041,6 +2112,23 @@ var RAYLEIGH = [0.192, 0.451, 1.0];
|
|||||||
var ATMO_AIR_GAIN = (typeof ATMO.airGain === 'number') ? Math.max(0.05, ATMO.airGain) : 0.55;
|
var ATMO_AIR_GAIN = (typeof ATMO.airGain === 'number') ? Math.max(0.05, ATMO.airGain) : 0.55;
|
||||||
var ATMO_HAZE_RESIDUAL = (typeof ATMO.hazeResidual === 'number')
|
var ATMO_HAZE_RESIDUAL = (typeof ATMO.hazeResidual === 'number')
|
||||||
? Math.max(0.02, Math.min(0.95, ATMO.hazeResidual)) : 0.30;
|
? Math.max(0.02, Math.min(0.95, ATMO.hazeResidual)) : 0.30;
|
||||||
|
var ATMO_DISTANCE_FOG = ATMO.distanceFog !== false;
|
||||||
|
var ATMO_MODEL = ATMO.model || {};
|
||||||
|
var ATMO_MODEL_ON = ATMO_MODEL.enabled !== false;
|
||||||
|
var ATMO_MODEL_HEIGHT_KM = (typeof ATMO_MODEL.heightKm === 'number')
|
||||||
|
? Math.max(1.0, Math.min(80.0, ATMO_MODEL.heightKm)) : 35.0;
|
||||||
|
var ATMO_MODEL_HEIGHT_UNITS = ATMO_MODEL_HEIGHT_KM / KM_PER_TILE;
|
||||||
|
var ATMO_MODEL_SCALE_HEIGHT_KM = (typeof ATMO_MODEL.scaleHeightKm === 'number')
|
||||||
|
? Math.max(1.0, Math.min(30.0, ATMO_MODEL.scaleHeightKm)) : 8.5;
|
||||||
|
var ATMO_MODEL_SCALE_HEIGHT_UNITS = ATMO_MODEL_SCALE_HEIGHT_KM / KM_PER_TILE;
|
||||||
|
var ATMO_MODEL_DENSITY = (typeof ATMO_MODEL.density === 'number')
|
||||||
|
? Math.max(0.01, Math.min(5.0, ATMO_MODEL.density)) : 0.12;
|
||||||
|
var ATMO_MODEL_GRAY_TAU = (typeof ATMO_MODEL.grayTau === 'number')
|
||||||
|
? Math.max(0.1, Math.min(10.0, ATMO_MODEL.grayTau)) : 1.5;
|
||||||
|
var ATMO_MODEL_GAIN = (typeof ATMO_MODEL.gain === 'number')
|
||||||
|
? Math.max(0.1, Math.min(5.0, ATMO_MODEL.gain)) : 2.0;
|
||||||
|
var ATMO_MODEL_BLUE_COLOR = new Float32Array([0.22, 0.42, 0.95]);
|
||||||
|
var ATMO_MODEL_GRAY_COLOR = new Float32Array([0.72, 0.76, 0.82]);
|
||||||
// Integrated starlight + airglow. Physically this is about a millionth of
|
// Integrated starlight + airglow. Physically this is about a millionth of
|
||||||
// daylight, so it is a stylised floor (CONFIG.atmosphere.starGain) that
|
// daylight, so it is a stylised floor (CONFIG.atmosphere.starGain) that
|
||||||
// keeps clouds, contrails and the ground from going fully black on a
|
// keeps clouds, contrails and the ground from going fully black on a
|
||||||
@@ -5112,6 +5200,15 @@ window.clouds3dRender = function(target) {
|
|||||||
gl.uniform3f(s.uMoonColor, _mBeam[0], _mBeam[1], _mBeam[2]);
|
gl.uniform3f(s.uMoonColor, _mBeam[0], _mBeam[1], _mBeam[2]);
|
||||||
gl.uniform1f(s.uMoonInt, _moonI);
|
gl.uniform1f(s.uMoonInt, _moonI);
|
||||||
gl.uniform1f(s.uSkyAmb, _amb * ATMO_SKY_GAIN);
|
gl.uniform1f(s.uSkyAmb, _amb * ATMO_SKY_GAIN);
|
||||||
|
gl.uniform1f(s.uAtmoModelOn, ATMO_MODEL_ON ? 1.0 : 0.0);
|
||||||
|
gl.uniform1f(s.uAtmoHeightUnits, ATMO_MODEL_HEIGHT_UNITS);
|
||||||
|
gl.uniform1f(s.uAtmoScaleHeightUnits, ATMO_MODEL_SCALE_HEIGHT_UNITS);
|
||||||
|
gl.uniform1f(s.uAtmoDensity, ATMO_MODEL_DENSITY);
|
||||||
|
gl.uniform1f(s.uAtmoGrayTau, ATMO_MODEL_GRAY_TAU);
|
||||||
|
gl.uniform1f(s.uAtmoGain, ATMO_MODEL_GAIN);
|
||||||
|
gl.uniform1f(s.uEarthRadius, EARTH_RADIUS_UNITS);
|
||||||
|
gl.uniform3fv(s.uAtmoBlueColor, ATMO_MODEL_BLUE_COLOR);
|
||||||
|
gl.uniform3fv(s.uAtmoGrayColor, ATMO_MODEL_GRAY_COLOR);
|
||||||
gl.uniform1f(s.uStarAmb, _star);
|
gl.uniform1f(s.uStarAmb, _star);
|
||||||
// Theme cloud hue kept, brightness normalised: the light model, not the
|
// Theme cloud hue kept, brightness normalised: the light model, not the
|
||||||
// palette, decides how bright a cloud is.
|
// palette, decides how bright a cloud is.
|
||||||
@@ -5937,6 +6034,12 @@ window.clouds3dRender = function(target) {
|
|||||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
gl.uniform1i(s.uMode, 1);
|
gl.uniform1i(s.uMode, 1);
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||||
|
|
||||||
|
if (ATMO_MODEL_ON) {
|
||||||
|
gl.uniform1i(s.uMode, 2);
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
// Restore default state for the next frame.
|
// Restore default state for the next frame.
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
gl.enable(gl.DEPTH_TEST);
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
|||||||
Reference in new issue
Block a user