atmosphere: replace flickering full-screen haze with stable terrain haze

This commit is contained in:
Richard Zink committed 2026-10-12 17:15:33 +02:00
1 parent 5146d17599
commit 989310ab3b
2 files changed
+71 -4

No files matched your search

+62 -3
View File
@@ -688,6 +688,12 @@ var TERRAIN_FRAG_SRC = [
'uniform vec3 uCamPos;', // world-space camera, for the view direction
'uniform float uEarthRadius;',
'uniform float uCurvatureOn;',
'uniform float uHazeOn;',
'uniform float uHazeDensity;',
'uniform float uHazeScaleHeightUnits;',
'uniform float uHazeGain;',
'uniform float uHazeMaxAlpha;',
'uniform vec3 uHazeColor;',
'uniform float uEdgeFadeTiles;',
'uniform vec3 uWireColor;', // non-zero -> debug wireframe overlay (flat colour)
'varying vec3 vNormal;',
@@ -697,6 +703,21 @@ var TERRAIN_FRAG_SRC = [
'varying vec3 vWorld;',
'varying vec3 vColor;',
CLOUD_SAMPLER_GLSL,
'float terrainHazeColumn(vec3 world) {',
'float dist = length(world - uCamPos);',
'if (dist <= 0.0) return 0.0;',
'if (uCurvatureOn < 0.5) return dist;',
'float R = max(1.0, uEarthRadius);',
'float Hs = max(0.05, uHazeScaleHeightUnits);',
'vec3 C = vec3(uCamPos.x, -R, uCamPos.z);',
'float column = 0.0;',
'for (int i = 0; i < 8; i++) {',
'vec3 p = mix(uCamPos, world, (float(i) + 0.5) / 8.0);',
'float alt = max(0.0, length(p - C) - R);',
'column += exp(-alt / Hs) * dist / 8.0 / Hs;',
'}',
'return column;',
'}',
'void main() {',
'vec2 gUv = vUV;',
// Edge fade: beyond the canvas the texture is clamped to the
@@ -784,12 +805,19 @@ var TERRAIN_FRAG_SRC = [
// veil but into the airlight itself - blue-biased (Rayleigh,
// 1/lambda^4) and brighter towards the sun through the (1+cos^2)/2
// phase function.
'float tau = uAirDensity * dist * (0.75 + 0.25 * smoothstep(0.4, 0.0, vY));',
'float trans = exp(-tau);',
'float hazeTau = 0.0;',
'if (uHazeOn > 0.5) {',
'hazeTau = uHazeDensity * terrainHazeColumn(vWorld);',
'} else {',
'hazeTau = uAirDensity * dist * (0.75 + 0.25 * smoothstep(0.4, 0.0, vY));',
'}',
'float trans = exp(-hazeTau);',
'vec3 vd = normalize(vWorld - uCamPos);',
'float cosT = dot(vd, uSunDir);',
'float rphase = 0.5 + 0.5 * cosT * cosT;',
'col = col * trans + uAirColor * rphase * (1.0 - trans);',
'float hazeAlpha = clamp((1.0 - trans) * uHazeGain, 0.0, uHazeMaxAlpha);',
'vec3 hazeCol = mix(uHazeColor, uAirColor, 0.25) * (0.75 + 0.25 * rphase);',
'col = mix(col, hazeCol, hazeAlpha);',
// Edge fade to the same horizon colour
'col = mix(horizonCol, col, edgeFade);',
// Wireframe overlay: when CONFIG.terrain.wireframe is set the
@@ -944,6 +972,12 @@ function init(canvas) {
var terrainUEarthRadius = terrainProg ? gl.getUniformLocation(terrainProg, 'uEarthRadius') : null;
var terrainUCurvatureOn = terrainProg ? gl.getUniformLocation(terrainProg, 'uCurvatureOn') : null;
var terrainUedgeFade = terrainProg ? gl.getUniformLocation(terrainProg, 'uEdgeFadeTiles') : null;
var terrainUHazeOn = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeOn') : null;
var terrainUHazeDensity = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeDensity') : null;
var terrainUHazeScale = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeScaleHeightUnits') : null;
var terrainUHazeGain = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeGain') : null;
var terrainUHazeMaxAlpha = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeMaxAlpha') : null;
var terrainUHazeColor = terrainProg ? gl.getUniformLocation(terrainProg, 'uHazeColor') : null;
var terrainUstarAmb = terrainProg ? gl.getUniformLocation(terrainProg, 'uStarAmb') : null;
var terrainUtime = terrainProg ? gl.getUniformLocation(terrainProg, 'uTime') : null;
var terrainUcloudbot = terrainProg ? gl.getUniformLocation(terrainProg, 'uCloudBot') : null;
@@ -1021,6 +1055,9 @@ function init(canvas) {
uCamPos: terrainUcampos,
uEarthRadius: terrainUEarthRadius, uCurvatureOn: terrainUCurvatureOn,
uEdgeFadeTiles: terrainUedgeFade,
uHazeOn: terrainUHazeOn, uHazeDensity: terrainUHazeDensity,
uHazeScaleHeightUnits: terrainUHazeScale, uHazeGain: terrainUHazeGain,
uHazeMaxAlpha: terrainUHazeMaxAlpha, uHazeColor: terrainUHazeColor,
uStarAmb: terrainUstarAmb,
uTime: terrainUtime, uCloudBot: terrainUcloudbot,
uCloudTop: terrainUcloudtop, uDensity: terrainUdensity,
@@ -2463,6 +2500,22 @@ var ATMO_MODEL_MAX_ALPHA = (typeof HAZE_CFG.maxAlpha === 'number')
? Math.max(0.05, Math.min(1.0, HAZE_CFG.maxAlpha))
: ((typeof ATMO_MODEL.maxAlpha === 'number')
? Math.max(0.05, Math.min(1.0, ATMO_MODEL.maxAlpha)) : 0.55);
var TERRAIN_HAZE_CFG = ATMO.terrainHaze || {};
var TERRAIN_HAZE_ON = TERRAIN_HAZE_CFG.enabled !== false;
var TERRAIN_HAZE_SCALE_HEIGHT_KM = (typeof TERRAIN_HAZE_CFG.scaleHeightKm === 'number')
? Math.max(1.0, Math.min(30.0, TERRAIN_HAZE_CFG.scaleHeightKm)) : 8.5;
var TERRAIN_HAZE_SCALE_HEIGHT_UNITS = TERRAIN_HAZE_SCALE_HEIGHT_KM / KM_PER_TILE;
var TERRAIN_HAZE_DENSITY = (typeof TERRAIN_HAZE_CFG.density === 'number')
? Math.max(0.01, Math.min(5.0, TERRAIN_HAZE_CFG.density)) : 0.22;
var TERRAIN_HAZE_GAIN = (typeof TERRAIN_HAZE_CFG.gain === 'number')
? Math.max(0.1, Math.min(5.0, TERRAIN_HAZE_CFG.gain)) : 1.0;
var TERRAIN_HAZE_MAX_ALPHA = (typeof TERRAIN_HAZE_CFG.maxAlpha === 'number')
? Math.max(0.05, Math.min(1.0, TERRAIN_HAZE_CFG.maxAlpha)) : 0.65;
var TERRAIN_HAZE_COLOR = new Float32Array(
Array.isArray(TERRAIN_HAZE_CFG.color) && TERRAIN_HAZE_CFG.color.length >= 3
? [TERRAIN_HAZE_CFG.color[0], TERRAIN_HAZE_CFG.color[1], TERRAIN_HAZE_CFG.color[2]]
: [0.58, 0.64, 0.72]
);
var CURV_CFG = (window.CONFIG && window.CONFIG.curvature) || {};
var CURVATURE_ON = CURV_CFG.enabled !== false;
var CURV_EXAG = (typeof CURV_CFG.exaggeration === 'number')
@@ -5845,6 +5898,12 @@ window.clouds3dRender = function(target) {
gl.uniform1f(terr.uEarthRadius, EARTH_RADIUS_UNITS);
gl.uniform1f(terr.uCurvatureOn, CURVATURE_ON ? 1.0 : 0.0);
gl.uniform1f(terr.uEdgeFadeTiles, EDGE_FADE_TILES);
gl.uniform1f(terr.uHazeOn, TERRAIN_HAZE_ON ? 1.0 : 0.0);
gl.uniform1f(terr.uHazeDensity, TERRAIN_HAZE_DENSITY);
gl.uniform1f(terr.uHazeScaleHeightUnits, TERRAIN_HAZE_SCALE_HEIGHT_UNITS);
gl.uniform1f(terr.uHazeGain, TERRAIN_HAZE_GAIN);
gl.uniform1f(terr.uHazeMaxAlpha, TERRAIN_HAZE_MAX_ALPHA);
gl.uniform3f(terr.uHazeColor, TERRAIN_HAZE_COLOR[0], TERRAIN_HAZE_COLOR[1], TERRAIN_HAZE_COLOR[2]);
gl.bindBuffer(gl.ARRAY_BUFFER, terr.vbo);
var STRIDE = 11 * 4; // 11 floats per vertex