Keep street maps legible on Navara after dusk

Navara lights the map tiles with the real sun and sky, and only the
landscape maps took the night ambient fill, so an OSM street map turned
black at local night where Cesium keeps it lit. Every base map now takes
the night fill; the landscape maps keep their orbital fill as well.
Daylight is unchanged.

This is why the strict acceptance's Navara pixel and first-frame checks
over Austin failed in evening runs: navara-hd, parked-release,
hidden-switch, context-loss, geo-import and scope saw a black frame, and
the soak and failure matrix waited for a first frame that never came.
At night with the fix all nine pass.
This commit is contained in:
German Khokhlov committed 2026-11-07 06:29:33 +04:00
1 parent 54fe0aea40
commit e18f12d34c
3 files changed
+32 -5

No files matched your search

+4 -3
View File
@@ -266,9 +266,10 @@ one application, and only the globe-bound parts move to the next engine.
tiles from a disk cache and a trap that fails any read of Cesium before it
has loaded. Every catalog layer must be asserted on both engines. Point
`PUPPETEER_EXECUTABLE_PATH` at an installed Chrome if Puppeteer's pinned
build is missing. With an OSM base map Navara lights the globe by the real
sun, so scenarios over Austin or San Francisco see a dark frame at local
night and fail their pixel checks; run them in local daylight.
build is missing. Navara lights the globe by the real sun; every base map,
street maps included, takes the night fill after dusk, so a scenario over
Austin or San Francisco at local night still sees a legible map, as on
Cesium (`src/globe/navara/look.js`).
- **Navara 0.2.1 workaround.** The SDK never frees pick batch ids, and the
mover banks rebuild their instanced meshes on each attach, so every switch
leaked one id per instance of capacity (about 260 KiB of WebAssembly memory).
+5 -2
View File
@@ -124,14 +124,17 @@ export function buildNavaraLook(
? atmosphere.getSunElevation(place)
: Number.NaN;
// Keep the map legible from orbit and when descending into darkness.
// At low altitude the fill increases from sunset to civil dusk.
// At low altitude the fill increases from sunset to civil dusk. Every
// base map takes the night fill: the tiles are lit by the sun and the
// sky, so a street map turned black after dusk, where Cesium (the
// reference) keeps it legible; the orbital fill stays the landscape's.
const orbitalFill = Number.isFinite(height)
? Math.min(1, Math.max(0, (height - 50_000) / 250_000))
: 0;
const nightFill = Number.isFinite(elevation)
? Math.min(1, Math.max(0, -elevation / 6))
: 0;
const nextFill = landscape ? Math.max(orbitalFill, nightFill) : 0;
const nextFill = landscape ? Math.max(orbitalFill, nightFill) : nightFill;
if (nextFill !== fill) {
fill = nextFill;
if (fillLight) fillLight.update({ ambient: { intensity: fill } });
+23
View File
@@ -248,6 +248,29 @@ test('inspection sunlight stays fixed through orbit, zoom and move end', () => {
assert.equal(view.atmosphere.date, restored);
});
test('a street map keeps the night fill after dusk, as Cesium keeps it lit', () => {
// OSM over Austin at 12 km on the live sun: not a landscape, so the sun
// is the wall clock's and the map has no orbital fill.
const view = fakeView(0);
const look = warmCinematic(view);
const austin = { lat: 30.27, lng: -97.74 };
let elevation = 40;
view.atmosphere.getSunElevation = () => elevation;
look.frame(12_000, false, 0, austin, false);
const ambient = () =>
view.added.find(({ desc }) => Object.hasOwn(desc, 'ambient'));
assert.equal(ambient(), undefined, 'no fill in daylight');
elevation = -3;
look.frame(12_000, false, 0, austin, false);
assert.equal(ambient().desc.ambient.intensity, 0.5, 'half at dusk');
elevation = -40;
look.frame(12_000, false, 0, austin, false);
assert.equal(ambient().updates.at(-1).ambient.intensity, 1, 'full at night');
elevation = 10;
look.frame(12_000, false, 0, austin, false);
assert.equal(ambient().updates.at(-1).ambient.intensity, 0, 'none by day');
});
test('the sun follows the wall clock, a minute at most behind, only on drawn frames', () => {
let now = 1_000_000;
const view = fakeView(now);