mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 15:52:21 +00:00
fix(globe): Navara sprites, points and lines drawn after tone mapping
Review of Tasks 2–3: on Navara the overlays went through the look's tone mapping and grading (magenta came out as 247/40/228, green as 147/228/89 in the cinematic look), where Cesium draws billboards and polylines in the colours asked for. src/globe/navara/overlay.js: a public Navara EffectDesc (gevOverlay) inserted after toneMapping and before the gev sharpening, SMAA/FXAA and final, whose pass renders one three scene over the tone-mapped input buffer (in Navara's own Pass wrapper: Navara inserts a bare pass only when it is an instance of its own postprocessing copy); it costs nothing while the scene is empty. The chain has no depth buffer, so each overlay material tests the scene depth itself (overlayDepth.js): its log depth against Navara's MRT depth (RGBA packed), modes always / normal / depth-fail, disableWithinM as a per-vertex escape. Sprites and points (moverMesh.js) and line ribbons (lineMesh.js) live in that scene with their per-frame work as overlay hooks; models stay Navara meshes, lit and graded like the tiles. The sharpening now sits after the overlay (Cesium's sharpen stage sharpens billboards too). Also (review): Navara pixel dashes are measured in CSS pixels (gl_FragCoord over uGevPixelRatio), and the line viewport uniform is updated in place. Measured: a magenta sprite draws 255/0/255. The contract suite's colour checks are now within 40 of the asked colour on every channel on both engines (were: dominant channels); Cesium 68/68, Navara 74/74 (its sharpen-order check accepts the overlay between tone mapping and the sharpening). Shell: cesium 23/23, cross 4/4; navara 23/25 — the two map stack pictures from space fail on stddev 7.2/7.6 against 8, as on the Task 3 commit run at the same hour (the cinematic sun follows the clock into night over the reset view), not from this change.
This commit is contained in:
1 parent
3c2e924363
commit
e804351205
11 files changed
+388
-125
No files matched your search
@@ -0,0 +1,133 @@
|
||||
// gev's screen overlays on Navara: sprites, points and lines (engine.movers
|
||||
// and engine.lines) drawn into the frame after Navara's tone mapping and
|
||||
// before its anti-aliasing (SMAA/FXAA) and the gev sharpening, so their
|
||||
// colours are the colours asked for (as Cesium draws billboards and
|
||||
// polylines), not tone-mapped or graded with the look. A public Navara
|
||||
// EffectDesc whose pass renders one three scene over the input buffer; the
|
||||
// post-processing chain has no depth buffer, so each overlay material tests
|
||||
// the scene depth from Navara's MRT pass itself (overlayDepth.js). The
|
||||
// pass costs nothing while the scene is empty. Models stay in Navara's
|
||||
// scene, lit and graded like the 3D tiles.
|
||||
|
||||
import { EffectDesc, Pass as NavaraPass } from '@navaramap/three';
|
||||
import { Pass } from 'postprocessing';
|
||||
import { RGBADepthPacking, Scene } from 'three';
|
||||
|
||||
export const OVERLAY_EFFECT_KEY = 'gevOverlay';
|
||||
|
||||
class GevOverlayPass extends Pass {
|
||||
constructor(scene, camera, overlay) {
|
||||
super('GevOverlayPass', scene, camera);
|
||||
this.needsSwap = false;
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
render(renderer, inputBuffer) {
|
||||
if (!this.scene.children.length) return;
|
||||
const resolution = this.overlay.uniforms.uGevResolution.value;
|
||||
resolution[0] = inputBuffer?.width ?? 0;
|
||||
resolution[1] = inputBuffer?.height ?? 0;
|
||||
const autoClear = renderer.autoClear;
|
||||
renderer.autoClear = false;
|
||||
renderer.setRenderTarget(this.renderToScreen ? null : inputBuffer);
|
||||
renderer.render(this.scene, this.camera);
|
||||
renderer.autoClear = autoClear;
|
||||
}
|
||||
}
|
||||
|
||||
class GevOverlayEffectDesc extends EffectDesc {
|
||||
static key = OVERLAY_EFFECT_KEY;
|
||||
static insertAfter = ['toneMapping'];
|
||||
static insertBefore = ['gevSharpen', 'smaa', 'fxaa', 'final'];
|
||||
|
||||
constructor(view, ctx, config) {
|
||||
super(view, ctx, config);
|
||||
this.overlay = config[OVERLAY_EFFECT_KEY].overlay;
|
||||
this.overlay.attach(ctx);
|
||||
}
|
||||
|
||||
createPass() {
|
||||
const camera = this.view.camera.raw;
|
||||
if (!camera) throw new Error('Camera not available for the overlay');
|
||||
// In Navara's own Pass wrapper: Navara inserts a bare pass only when
|
||||
// it is an instance of its own postprocessing copy.
|
||||
return new NavaraPass(
|
||||
new GevOverlayPass(this.overlay.scene, camera, this.overlay),
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
// Each drawn frame: the scene depth the overlays test against, then each
|
||||
// overlay's own per-frame work (pixel footprint, origin, viewport).
|
||||
update(time) {
|
||||
const mrt = this.find('mrt');
|
||||
this.overlay.uniforms.tGevSceneDepth.value =
|
||||
mrt?.depthBufferPacking === RGBADepthPacking ? mrt.depthBuffer : null;
|
||||
this.overlay.beforeFrame(time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The overlay of one view: add(object, onFrame) puts a three object in the
|
||||
* overlay scene (onFrame runs each drawn frame before it draws);
|
||||
* registerPickable/unregisterPickable reach Navara's pick pass.
|
||||
* @param {object} view an initialised ThreeView
|
||||
*/
|
||||
export function createNavaraOverlay(view) {
|
||||
view.registerEffect(OVERLAY_EFFECT_KEY, GevOverlayEffectDesc);
|
||||
const scene = new Scene();
|
||||
const frameHooks = new Map();
|
||||
let ctx = null;
|
||||
const pendingPicks = new Map();
|
||||
const overlay = {
|
||||
scene,
|
||||
uniforms: {
|
||||
tGevSceneDepth: { value: null },
|
||||
uGevResolution: { value: [0, 0] },
|
||||
},
|
||||
attach(context) {
|
||||
ctx = context;
|
||||
for (const [key, wrapper] of pendingPicks)
|
||||
ctx.registerPickableMesh(key, wrapper);
|
||||
pendingPicks.clear();
|
||||
},
|
||||
beforeFrame(time) {
|
||||
for (const hook of frameHooks.values()) hook(time);
|
||||
},
|
||||
get ctx() {
|
||||
return ctx;
|
||||
},
|
||||
};
|
||||
const handle = view.addEffect({
|
||||
[OVERLAY_EFFECT_KEY]: { overlay },
|
||||
visible: true,
|
||||
});
|
||||
return {
|
||||
scene,
|
||||
uniforms: overlay.uniforms,
|
||||
add(object, onFrame) {
|
||||
scene.add(object);
|
||||
if (onFrame) frameHooks.set(object, onFrame);
|
||||
},
|
||||
remove(object) {
|
||||
scene.remove(object);
|
||||
frameHooks.delete(object);
|
||||
},
|
||||
registerPickable(key, wrapper) {
|
||||
if (ctx) ctx.registerPickableMesh(key, wrapper);
|
||||
else pendingPicks.set(key, wrapper);
|
||||
},
|
||||
unregisterPickable(key) {
|
||||
pendingPicks.delete(key);
|
||||
ctx?.unregisterPickableMesh(key);
|
||||
},
|
||||
get ctx() {
|
||||
return ctx;
|
||||
},
|
||||
destroy() {
|
||||
handle.delete();
|
||||
scene.clear();
|
||||
frameHooks.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user