mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-10 21:32:23 +00:00
Add raster imagery to the globe contract and draw FIRMS heat and Recent Imagery through it
engine.imagery draws raster layers over the globe: Web Mercator tile templates and single images or canvases stretched over a rectangle, with alpha, show, a left/right split against the engine's split position and an order. A layer's source can be replaced in place. - Cesium puts one ImageryLayer per layer on the globe's imagery stack, or on the shown 3D tileset's when the globe is hidden, and moves it when the surface changes; the Recent Imagery request gate moved here. - Navara draws them in one screen pass after tone mapping that samples up to eight layers by geodetic position from mipmapped textures and a tile atlas, under the other drapes and engine.ground. - The fake engine keeps each layer's state. The FIRMS far-zoom heat raster and Recent Imagery now draw through it, so FIRMS' heat seam and both its backends, and Recent Imagery's Cesium and Navara renderers and tile plan, go. Against HEAD, Cesium's pixels are identical in all four compared scenes; Navara's orbital heat changes by a mean of 3.8 from new mipmapping, slightly towards Cesium. The contract suite passes on both engines (Cesium 68/68, Navara 71/71). engine.maps.addOverlay stays a Navara-only extension for Sea Marks and Ski Pistes until imagery has a finer tile path for oblique global views.
This commit is contained in:
1 parent
1559bd57f4
commit
406dd9122e
52 files changed
+4171
-1988
No files matched your search
+27
-7
@@ -183,8 +183,10 @@ one application, and only the globe-bound parts move to the next engine.
|
||||
`node scripts/qa-contract-suite.mjs <origin>` runs them in headless Chrome
|
||||
on the real Cesium and Navara of a keyless dev server, with a real pointer
|
||||
and real canvases; checks of state the app drives itself (contact sonar)
|
||||
are skipped and named. On November 7, 2026 Cesium passed 66 of 66 and
|
||||
Navara 69 of 69. `movers` and `lines` are required of every engine: Cesium
|
||||
are skipped and named. On November 7, 2026, with the imagery checks,
|
||||
Cesium passed 68 of 68 and Navara 71 of 71 (the camera-events check now
|
||||
and then misses its moveEnd on a busy machine on either engine and passes
|
||||
when run again). `movers` and `lines` are required of every engine: Cesium
|
||||
draws them with billboards, points, models and polyline primitives
|
||||
(`src/globe/cesium/movers.js`, `lines.js`).
|
||||
- **Fills on the ground** (`engine.ground`) are required of every engine
|
||||
@@ -202,6 +204,26 @@ one application, and only the globe-bound parts move to the next engine.
|
||||
perimeters have prototypes in `render/ground.js`.
|
||||
- On November 7, 2026, `scripts/qa-ground-suite.mjs` (the ground checks
|
||||
with pixels) passed 3 of 3 on both engines.
|
||||
- **Rasters on the ground** (`engine.imagery`) are required of every engine
|
||||
too: layers of Web Mercator tiles from a URL template or of one image (a
|
||||
canvas, an image, RGBA bytes or an image URL) over a rectangle, each with
|
||||
its alpha, show, split side and draw `order`, and one split position per
|
||||
engine (`docs/GLOBE-PRIMITIVES.md`).
|
||||
- Cesium draws each as an `ImageryLayer` on the imagery stack of the
|
||||
surface shown (the globe, or the shown 3D tileset's), and follows it
|
||||
(`src/globe/cesium/imagery.js`).
|
||||
- Navara draws them in one screen pass after tone mapping, classified on
|
||||
the scene depth (`src/globe/navara/imagery/`).
|
||||
- Active Fires' far-zoom heatmap and Recent Imagery draw through it;
|
||||
weather, wind and the Bhote Koshi event imagery do not yet.
|
||||
- `engine.maps.addOverlay` (Navara's native raster layers for Sea Marks
|
||||
and Ski Pistes) stays until those overlays move to `engine.imagery`.
|
||||
- On November 7, 2026, `scripts/qa-ground-suite.mjs --only=imagery:` (the
|
||||
imagery checks with pixels) passed 2 of 2 on both engines, and
|
||||
`scripts/qa-imagery-compare.mjs` found the heatmap and Recent Imagery
|
||||
drawn as before on Cesium (no pixel changed where they draw) and on
|
||||
Navara (no channel off by more than 1 of 255, but for the heatmap from
|
||||
orbit, which Navara now mipmaps as Cesium does).
|
||||
- **Engine coupling.** `node scripts/report-engine-coupling.mjs` counts the
|
||||
engine-specific code outside the engines: renderer lines per engine, Cesium
|
||||
imports, `viewer` mentions, engine-name checks, raw Navara reads, Navara
|
||||
@@ -233,11 +255,9 @@ one application, and only the globe-bound parts move to the next engine.
|
||||
`src/layers/awareness/render/pulseDisc.js` (`render/cesiumPulses.js`, a
|
||||
material disc, on Cesium; `render/navaraPulses.js`, a surface pass that the
|
||||
Navara mode loads and passes in).
|
||||
The Active Fires far-zoom heatmap, a raster draped on the ground that the
|
||||
contract has no primitive for yet, draws behind one seam,
|
||||
`src/layers/firms/render/heatField.js` (`render/cesiumHeat.js`, an imagery
|
||||
layer, on Cesium; `render/navaraHeat.js`, a surface pass that the Navara
|
||||
mode loads and passes in). CCTV's monitor plane and viewshed volume, which the
|
||||
The Active Fires far-zoom heatmap is an `engine.imagery` layer, and Recent
|
||||
Imagery draws its days through `engine.imagery` from its own
|
||||
`render/display.js`. CCTV's monitor plane and viewshed volume, which the
|
||||
contract has no primitive for yet, draw behind one seam,
|
||||
`src/layers/cctv/render/meshes.js` (`render/cesiumMeshes.js` on Cesium;
|
||||
`render/navaraMeshes.js`, which the Navara mode loads and passes in). Cesium
|
||||
|
||||
+118
-3
@@ -1,13 +1,14 @@
|
||||
# Globe primitives
|
||||
|
||||
A layer draws through the globe-engine contract (`src/globe/contract.js`),
|
||||
not through Cesium or Navara. The contract has three drawing primitives:
|
||||
not through Cesium or Navara. The contract has four drawing primitives:
|
||||
|
||||
- `engine.movers`: things at points;
|
||||
- `engine.lines`: lines in the air;
|
||||
- `engine.ground`: fills on the ground.
|
||||
- `engine.ground`: fills on the ground;
|
||||
- `engine.imagery`: rasters on the ground.
|
||||
|
||||
Each engine implements all three. Cesium's are in `src/globe/cesium/`,
|
||||
Each engine implements all four. Cesium's are in `src/globe/cesium/`,
|
||||
Navara's in `src/globe/navara/`, and the fake engine's in
|
||||
`src/globe/testing/fakeEngine.js`. The checks every engine must pass are in
|
||||
`src/globe/testing/contractSuite.mjs`.
|
||||
@@ -211,6 +212,118 @@ take 135 ms. A layer with more lines than that (Street Level's up to 14 400
|
||||
sequences) needs a set-wide grid of bins first, as areas have, before it
|
||||
moves to `engine.ground`.
|
||||
|
||||
## Imagery: rasters on the ground
|
||||
|
||||
`engine.imagery.createLayer({ id, source, alpha, show, split, order })`
|
||||
makes one raster layer draped over the terrain and the 3D tiles, under
|
||||
every ground fill, mover, line and model. Its colours are the image's own,
|
||||
blended by the texel's alpha times the layer's `alpha`.
|
||||
|
||||
There are two kinds of source:
|
||||
|
||||
| kind | source | for |
|
||||
| ------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| `tiles` | `url` with `{z}`, `{x}`, `{y}` (and `{s}` of `subdomains`), `minLevel`, `maxLevel`, `tileSize` | Recent Imagery's GIBS days, weather tiles, open overlays |
|
||||
| `image` | `image`: a canvas, an ImageBitmap or image element, or `{ width, height, data }` RGBA bytes; or `url` | the FIRMS heat raster, a field image, event imagery |
|
||||
|
||||
Both take:
|
||||
|
||||
- `rectangle` (`{ west, south, east, north }` in degrees; west > east
|
||||
crosses the antimeridian): where the layer draws, the globe when omitted;
|
||||
- `credit`: HTML shown while the layer is.
|
||||
|
||||
Tiles are Web Mercator XYZ tiles and stop at ±85.05°. `opaque` tiles have
|
||||
no alpha channel, and `maxRequests` caps the layer's tile requests in
|
||||
flight. An image is stretched over its rectangle in longitude and latitude,
|
||||
row 0 on the north edge; one over the whole globe wraps across 180°.
|
||||
|
||||
Work with a layer like this:
|
||||
|
||||
- `setSource(source)` draws another source in its place, at its place in
|
||||
the order; the same canvas or bytes again draw their new pixels;
|
||||
- `setAlpha(alpha)` fades it: at 0 it draws nothing but stays on its
|
||||
surface, so it comes back without a gap (the FIRMS hand-off);
|
||||
- `show(visible)` shows or hides it (Cesium unmaps a hidden layer's tiles);
|
||||
- `setSplit('left' | 'right' | 'none')` puts it on one side of the split;
|
||||
- `ready()` says the source is built (an image URL loaded); tiles arrive
|
||||
after it;
|
||||
- `destroy()`.
|
||||
|
||||
On the engine:
|
||||
|
||||
- `list()` names the layers in draw order, bottom first: a higher `order`
|
||||
draws on top, then the later layer;
|
||||
- `setSplitPosition(fraction)` sets where the split runs, a fraction of the
|
||||
canvas width from the left (one per engine, Cesium's
|
||||
`scene.splitPosition`); `splitPosition()` reads it;
|
||||
- `surface()` says where imagery drapes now: `'globe'`, `'tiles'` (3D tiles)
|
||||
or `'none'`.
|
||||
|
||||
### How each engine draws imagery
|
||||
|
||||
**Cesium** (`src/globe/cesium/imagery.js`) gives each layer one
|
||||
`ImageryLayer`:
|
||||
|
||||
- on the globe's imagery layers while the globe shows, else on the shown 3D
|
||||
tileset's own imagery layers (Cesium drapes imagery on tiles there), as
|
||||
`src/maps/imageryHost.js` resolves it for the shell; with neither, the
|
||||
layers wait;
|
||||
- the engine checks the surface on every frame while it holds a layer, and
|
||||
builds each layer again on the new stack after a switch;
|
||||
- above the base imagery, in order among the engine's layers; imagery other
|
||||
code adds stays where it was put;
|
||||
- tiles: a `UrlTemplateImageryProvider` in Web Mercator, bounded to the
|
||||
rectangle; `maxRequests` gates `requestImage`, and a request the gate or
|
||||
the provider defers asks for one delayed frame, never one per frame;
|
||||
- an image: one geographic tile over the rectangle (as
|
||||
`SingleTileImageryProvider`), handed to Cesium as the canvas or image
|
||||
itself, with no PNG round trip;
|
||||
- `split` is the layer's `splitDirection`; Cesium splits on the globe only.
|
||||
|
||||
**Navara** (`src/globe/navara/imagery/`) draws every shown layer in one
|
||||
screen pass right after tone mapping, under the other drapes and
|
||||
`engine.ground`:
|
||||
|
||||
- each pixel's ground position comes from the scene depth (terrain and 3D
|
||||
tiles), as `engine.ground`'s pass finds it;
|
||||
- up to 8 layers are sampled in draw order at its longitude and latitude,
|
||||
each in its rectangle and on its side of the split (the top 8 when more
|
||||
are shown);
|
||||
- an image is one mipmapped texture, sampled in longitude and latitude;
|
||||
- tiles are an atlas of at most 8×8 Web Mercator tiles over the part of the
|
||||
rectangle in view, at the level the camera's height asks for; it is
|
||||
rebuilt when the camera moves to another plan and filled as tiles arrive,
|
||||
6 loads at a time (or `maxRequests`);
|
||||
- texels are blended in display space, as Cesium's globe blends imagery;
|
||||
mip levels come from the derivatives of the ground position, taken
|
||||
before any branch, so rectangle edges and the antimeridian show no seams.
|
||||
|
||||
`engine.imagery` is the successor of `engine.maps.addOverlay`, Navara's
|
||||
undocumented extension for the open map overlays (Sea Marks, Ski Pistes).
|
||||
That one adds a native Navara raster layer: Navara's own per-tile levels on
|
||||
the terrain, lit like the base map, but no rectangle, split, alpha or order,
|
||||
and nothing on 3D tiles. It stays until those overlays move, which needs a
|
||||
finer Navara tiles path first: a global overlay seen obliquely gets coarse
|
||||
near the camera from one 8×8 atlas over the whole view.
|
||||
|
||||
### What is still to move
|
||||
|
||||
- **Weather radar, satellite clouds and lightning** (`src/layers/weather/`):
|
||||
tile templates in geographic and Web Mercator tilings, decoded canvases
|
||||
tiled into a provider, staged frames (a new frame loads under the shown
|
||||
one at alpha 0 and replaces it once its tiles are in), a per-tile image
|
||||
transform (the infrared mask), a detail window over the global image,
|
||||
and the raised shells Cesium draws over 3D tiles at a height. They need a
|
||||
geographic `tiles` scheme, a staged `setSource` (or `ready()` per tile
|
||||
set) and a tile transform; the raised shell is a separate primitive.
|
||||
- **The wind field** (`src/layers/wind/`): one image over the globe at a
|
||||
fixed alpha, faded by camera height — an `image` layer — and the same
|
||||
raised shell on 3D tiles.
|
||||
- **The Bhote Koshi event imagery** (`src/layers/bhoteKoshi/`, Cesium in
|
||||
`src/data/bhoteKoshiEvent.js`): two image URLs over one rectangle, split
|
||||
left and right, alpha 0.96 — two `image` layers with `url` and `split`.
|
||||
Navara still draws them with `src/layers/recentImagery/render/navaraGround.js`.
|
||||
|
||||
### Choosing a primitive
|
||||
|
||||
- **A position and an on-screen size:** a mover.
|
||||
@@ -224,3 +337,5 @@ moves to `engine.ground`.
|
||||
- Group items that change together into one set, and replace them in bulk.
|
||||
A ground set is rebuilt on every commit, so an animated fill (a pulse, a
|
||||
flowing route) is not a ground set yet.
|
||||
- **Pixels on the ground** (tiles, a raster, a photo): an imagery layer.
|
||||
Fade it with `setAlpha`, and give a new raster to `setSource`.
|
||||
Reference in new issue
Block a user