// The Active Fires far-zoom heatmap on Navara: the same equirectangular heat // raster the Cesium globe drapes as imagery (firmsHeatRaster.js), drawn over // visible terrain and 3D tiles by one non-pickable classification pass. Only // surface pixels take it, so the fire markers above stay untouched. The // adapter has heatImagery.js's interface, so the layer drives both alike. import { Effect, EffectAttribute } from 'postprocessing'; import { DataTexture, LinearFilter, Matrix4, RGBAFormat, RepeatWrapping, ClampToEdgeWrapping, Uniform, UnsignedByteType, } from 'three'; import { groundSurfaceUniforms, updateGroundSurface, } from '../../shared/render/navaraGroundSurface.js'; const KEY = 'gevFirmsHeat'; const registeredViews = new WeakSet(); // Row 0 of the raster is the north edge and column 0 is 180°W; the texture // keeps that order (no flip), so v = 0 is north. const fragmentShader = /* glsl */ ` uniform sampler2D tAllDepth; uniform sampler2D tSurfaceDepth; uniform sampler2D tHeat; uniform mat4 uInverseProjection; uniform mat4 uInverseView; uniform float uLogDepthFC; uniform float uOpacity; // WGS84 first eccentricity squared: geodetic latitude of a near-surface point. const float E2=0.0066943799901413165; vec3 toDisplay(vec3 c) { return mix(12.92*c,1.055*pow(max(c,vec3(0.0)),vec3(1.0/2.4))-0.055,step(vec3(0.0031308),c)); } vec3 toLinear(vec3 c) { return mix(c/12.92,pow(max((c+0.055)/1.055,vec3(0.0)),vec3(2.4)),step(vec3(0.04045),c)); } void mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor) { outputColor=inputColor; float depth=unpackRGBAToDepth(texture2D(tAllDepth,uv)); if(depth>=1.0) return; float surface=texture2D(tSurfaceDepth,uv).r; if(depth 0); if (!handle && visible) handle = view.addEffect({ [KEY]: { owner }, visible: true }); else handle?.update({ visible }); engine.render.request('firms-heat'); } return { setRaster(next) { if (destroyed) return; raster = next; owner.texture?.dispose(); owner.texture = next ? heatTexture(next) : null; sync(); }, /** True once a raster was handed over. */ hasRaster() { return raster !== null; }, setShow(value) { show = Boolean(value); sync(); }, /** Hand-off fade, 0..1. */ setOpacity(value) { owner.opacity = Math.min(1, Math.max(0, Number(value) || 0)); sync(); }, /** Navara drapes on its own surface; there is no imagery host to follow. */ rehome() {}, destroy() { if (destroyed) return; destroyed = true; handle?.delete(); handle = null; owner.texture?.dispose(); owner.texture = null; raster = null; engine.render.request('firms-heat-destroy'); }, }; }