Keep Navara terrain visible on night-side descents

This commit is contained in:
German Khokhlov committed 2026-11-02 20:58:17 +04:00
1 parent 3a2a53aef9
commit 96ce795f8c
2 files changed
+56 -18

No files matched your search

+21 -18
View File
@@ -108,24 +108,6 @@ export function buildNavaraLook(
tone.update({ toneMapping: { mode: landscape ? AGX : ACES_FILMIC } });
changed = true;
}
// In orbit, retain some of the underlying imagery in the atmospheric
// shadow. Fade up with altitude so ground views keep their original light.
const nextFill =
landscape && Number.isFinite(height)
? Math.min(1, Math.max(0, (height - 50_000) / 250_000))
: 0;
if (nextFill !== fill) {
fill = nextFill;
if (fillLight) fillLight.update({ ambient: { intensity: fill } });
else fillLight = view.addLight({ ambient: { intensity: fill } });
changed = true;
}
const opacity = aerial?.ref?.raw?.rawEffect?.blendMode.opacity;
const strength = 1 - 0.2 * fill;
if (opacity && opacity.value !== strength) {
opacity.value = strength;
changed = true;
}
const atmosphere = view.atmosphere;
// Choose inspection daylight once. Rotating the camera must not rotate
// the terminator across the geography.
@@ -140,6 +122,27 @@ export function buildNavaraLook(
place && typeof atmosphere?.getSunElevation === 'function'
? 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.
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;
if (nextFill !== fill) {
fill = nextFill;
if (fillLight) fillLight.update({ ambient: { intensity: fill } });
else fillLight = view.addLight({ ambient: { intensity: fill } });
changed = true;
}
const opacity = aerial?.ref?.raw?.rawEffect?.blendMode.opacity;
const strength = 1 - 0.2 * fill;
if (opacity && opacity.value !== strength) {
opacity.value = strength;
changed = true;
}
if (warmUp) {
warmUp -= 1;
aerial.update(warmUp ? IRRADIANCE_ON : IRRADIANCE_OFF);
+35
View File
@@ -193,6 +193,41 @@ test('daylight inspection restores live exposure, tone mapping and time when lef
assert.equal(view.atmosphere.date.getTime(), 0);
});
test('the dark side retains satellite imagery down to the surface', () => {
const view = fakeView(0);
const look = warmCinematic(view);
const aerial = view.added.find(({ desc }) =>
Object.hasOwn(desc, 'aerialPerspective'),
);
const opacity = { value: 1 };
aerial.ref = { raw: { rawEffect: { blendMode: { opacity } } } };
const origin = { lat: 21.975, lng: 20.9038 };
const fuji = { lat: 35.2599, lng: 138.6574 };
let elevation = 40;
view.atmosphere.getSunElevation = () => elevation;
look.frame(33_529_370, false, 0, origin, true);
const sun = view.atmosphere.date;
const ambient = view.added.find(({ desc }) => Object.hasOwn(desc, 'ambient'));
elevation = -30;
for (const height of [2_000_000, 100_000, 50_000, 6508, 600]) {
look.frame(height, true, 0, fuji, true);
assert.equal(opacity.value, 0.8);
assert.equal(
ambient.updates.length,
0,
'the orbital fill remains at full strength',
);
assert.equal(view.atmosphere.date, sun);
}
elevation = -3;
look.frame(600, false, 0, fuji, true);
assert.equal(ambient.updates.at(-1).ambient.intensity, 0.5);
elevation = 10;
look.frame(600, false, 0, origin, true);
assert.equal(ambient.updates.at(-1).ambient.intensity, 0);
assert.equal(opacity.value, 1);
});
test('inspection sunlight stays fixed through orbit, zoom and move end', () => {
const view = fakeView(0);
const look = warmCinematic(view);