mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 13:52:19 +00:00
Merge branch 'german/refactor-navara-tiles-drape-2' into german/navara-refactor
This commit is contained in:
commit
4bbf9949d5
2 files changed
+382
-7
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import * as geo from '../src/geo/index.js';
|
import * as geo from '../src/geo/index.js';
|
||||||
|
import { GROUND_SURFACE_GLSL } from '../src/globe/navara/ground/surface.js';
|
||||||
import {
|
import {
|
||||||
assertKeylessPreview,
|
assertKeylessPreview,
|
||||||
createStrict,
|
createStrict,
|
||||||
@@ -237,13 +238,22 @@ await strict.run({}, async (browser) => {
|
|||||||
// Map imagery and classification shaders may still be arriving before ready.
|
// Map imagery and classification shaders may still be arriving before ready.
|
||||||
await page.evaluate(() => window.qaDrape.show(false));
|
await page.evaluate(() => window.qaDrape.show(false));
|
||||||
await loaded(page);
|
await loaded(page);
|
||||||
const baseline = await pixels(page, position);
|
const before = await pixels(page, position);
|
||||||
await page.evaluate(() => window.qaDrape.show(true));
|
await page.evaluate(() => window.qaDrape.show(true));
|
||||||
const rgb = await pixels(page, position);
|
const shown = await pixels(page, position);
|
||||||
await page.evaluate(() => window.qaDrape.show(false));
|
await page.evaluate(() => window.qaDrape.show(false));
|
||||||
const restored = await pixels(page, position);
|
const after = await pixels(page, position);
|
||||||
|
const baseline = before.rgb;
|
||||||
|
const rgb = shown.rgb;
|
||||||
|
const restored = after.rgb;
|
||||||
const drawn = rgb[0] > 180 && rgb[1] < 80 && rgb[2] > 180;
|
const drawn = rgb[0] > 180 && rgb[1] < 80 && rgb[2] > 180;
|
||||||
const sample = { surface, drape, baseline, rgb, restored, drawn };
|
const sample = { surface, drape, baseline, rgb, restored, drawn };
|
||||||
|
if (report && kind === 'navara')
|
||||||
|
sample.depths = {
|
||||||
|
baseline: before.depths,
|
||||||
|
shown: shown.depths,
|
||||||
|
restored: after.depths,
|
||||||
|
};
|
||||||
drapes.push(sample);
|
drapes.push(sample);
|
||||||
console.log(
|
console.log(
|
||||||
`${report ? 'REPORT' : 'DRAPE'} ${kind} ${JSON.stringify(sample)}`,
|
`${report ? 'REPORT' : 'DRAPE'} ${kind} ${JSON.stringify(sample)}`,
|
||||||
@@ -320,13 +330,24 @@ async function loaded(page) {
|
|||||||
|
|
||||||
// Read actual canvas pixels during postRender; Cesium discards them afterwards.
|
// Read actual canvas pixels during postRender; Cesium discards them afterwards.
|
||||||
async function pixels(page, position) {
|
async function pixels(page, position) {
|
||||||
return page.evaluate(async (position) => {
|
const input = {
|
||||||
|
position,
|
||||||
|
diagnostic: report ? readNavaraDrape.toString() : null,
|
||||||
|
classification: GROUND_SURFACE_GLSL,
|
||||||
|
};
|
||||||
|
const sample = await page.evaluate(async (input) => {
|
||||||
|
const { position, diagnostic, classification } = input;
|
||||||
const { engine } = window.__godsEyeView;
|
const { engine } = window.__godsEyeView;
|
||||||
|
const readDepths =
|
||||||
|
diagnostic && engine.kind === 'navara'
|
||||||
|
? new Function(`return (${diagnostic})`)()
|
||||||
|
: null;
|
||||||
|
let depths;
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = canvas.height = 5;
|
canvas.width = canvas.height = 5;
|
||||||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||||||
for (let frame = 0; frame < 2; frame++)
|
for (let frame = 0; frame < 2; frame++)
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve, reject) => {
|
||||||
const off = engine.frames.postRender.addEventListener(() => {
|
const off = engine.frames.postRender.addEventListener(() => {
|
||||||
off();
|
off();
|
||||||
const point = engine.projector.worldToWindow(position);
|
const point = engine.projector.worldToWindow(position);
|
||||||
@@ -343,19 +364,147 @@ async function pixels(page, position) {
|
|||||||
5,
|
5,
|
||||||
5,
|
5,
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
|
if (readDepths)
|
||||||
|
depths = readDepths(engine, point, classification);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
engine.render.request('qa-drape-pixels');
|
engine.render.request('qa-drape-pixels');
|
||||||
});
|
});
|
||||||
const data = context.getImageData(0, 0, 5, 5).data;
|
const data = context.getImageData(0, 0, 5, 5).data;
|
||||||
return [0, 1, 2].map(
|
const rgb = [0, 1, 2].map(
|
||||||
(channel) =>
|
(channel) =>
|
||||||
data.reduce(
|
data.reduce(
|
||||||
(sum, value, i) => sum + (i % 4 === channel ? value : 0),
|
(sum, value, i) => sum + (i % 4 === channel ? value : 0),
|
||||||
0,
|
0,
|
||||||
) / 25,
|
) / 25,
|
||||||
);
|
);
|
||||||
}, position);
|
return { rgb, depths };
|
||||||
|
}, input);
|
||||||
|
if (sample.depths) {
|
||||||
|
const place =
|
||||||
|
sample.depths.position &&
|
||||||
|
geo.cartographic.fromCartesian(sample.depths.position);
|
||||||
|
const detail =
|
||||||
|
place &&
|
||||||
|
(await page.evaluate(
|
||||||
|
(place) =>
|
||||||
|
window.__godsEyeView.engine.surface.sampleHeightDetailed(place),
|
||||||
|
place,
|
||||||
|
));
|
||||||
|
sample.depths.source = detail?.source ?? null;
|
||||||
|
sample.depths.height = detail?.height ?? null;
|
||||||
|
}
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs in the page, after rendering. Read the centre of the same 5x5 colour
|
||||||
|
// sample, using the ground effect's actual uniforms and shader when shown.
|
||||||
|
function readNavaraDrape(engine, point, classification) {
|
||||||
|
const view = engine.extensions.navara.view;
|
||||||
|
const ctx = view.viewContext;
|
||||||
|
const renderer = ctx.getRenderer();
|
||||||
|
const mrt = ctx.findEffect('mrt');
|
||||||
|
const effect = ctx.findEffect('gevGround')?.effect;
|
||||||
|
const names = ['tAllDepth', 'tSurfaceDepth', 'tGlobeDepth'];
|
||||||
|
const textures = effect
|
||||||
|
? names.map((name) => effect.uniforms.get(name).value)
|
||||||
|
: [
|
||||||
|
mrt.depthBuffer,
|
||||||
|
ctx.getRenderTarget().depthTexture,
|
||||||
|
mrt.globeDepthBuffer,
|
||||||
|
];
|
||||||
|
if (effect)
|
||||||
|
classification = effect
|
||||||
|
.getFragmentShader()
|
||||||
|
.match(/float groundSurfaceType\([\s\S]*?\n}/)?.[0];
|
||||||
|
if (!classification) throw new Error('Missing ground classification shader');
|
||||||
|
const scale = engine.host.canvas.width / engine.host.size().width;
|
||||||
|
const canvasPixel = [
|
||||||
|
Math.round(point.x * scale),
|
||||||
|
Math.round(point.y * scale),
|
||||||
|
];
|
||||||
|
const size = textures[0].image;
|
||||||
|
const pixel = [
|
||||||
|
Math.floor(
|
||||||
|
((canvasPixel[0] + 0.5) * size.width) / engine.host.canvas.width,
|
||||||
|
),
|
||||||
|
Math.floor(
|
||||||
|
((engine.host.canvas.height - canvasPixel[1] - 0.5) * size.height) /
|
||||||
|
engine.host.canvas.height,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
// Use the installed SDK's depth-copy pass and Three packing. Four RGBA8
|
||||||
|
// pixels preserve the three depths and the shader's classification result.
|
||||||
|
const copy = new mrt.raw.globeDepthCopyPass.constructor();
|
||||||
|
const previous = renderer.getRenderTarget();
|
||||||
|
try {
|
||||||
|
copy.setSize(4, 1);
|
||||||
|
const material = copy.fullscreenMaterial;
|
||||||
|
material.uniforms = Object.fromEntries(
|
||||||
|
names.map((name, i) => [name, { value: textures[i] }]),
|
||||||
|
);
|
||||||
|
material.uniforms.pixel = { value: pixel };
|
||||||
|
material.fragmentShader = `
|
||||||
|
#include <packing>
|
||||||
|
uniform sampler2D tAllDepth;
|
||||||
|
uniform sampler2D tSurfaceDepth;
|
||||||
|
uniform sampler2D tGlobeDepth;
|
||||||
|
uniform ivec2 pixel;
|
||||||
|
${classification}
|
||||||
|
void main() {
|
||||||
|
float depth = unpackRGBAToDepth(texelFetch(tAllDepth, pixel, 0));
|
||||||
|
float surface = texelFetch(tSurfaceDepth, pixel, 0).r;
|
||||||
|
float globe = unpackRGBAToDepth(texelFetch(tGlobeDepth, pixel, 0));
|
||||||
|
int column = int(gl_FragCoord.x);
|
||||||
|
gl_FragColor = column == 3
|
||||||
|
? vec4(groundSurfaceType(depth, surface, globe) / 255.0, 0.0, 0.0, 1.0)
|
||||||
|
: packDepthToRGBA(column == 0 ? depth : column == 1 ? surface : globe);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
copy.render(renderer);
|
||||||
|
const bytes = new Uint8Array(16);
|
||||||
|
renderer.readRenderTargetPixels(copy.renderTarget, 0, 0, 4, 1, bytes);
|
||||||
|
const gl = renderer.getContext();
|
||||||
|
const error = gl.getError();
|
||||||
|
if (error !== gl.NO_ERROR)
|
||||||
|
throw new Error(`Depth diagnostic WebGL error: ${error}`);
|
||||||
|
const unpack = (offset) =>
|
||||||
|
bytes[offset] / 256 +
|
||||||
|
bytes[offset + 1] / 65536 +
|
||||||
|
bytes[offset + 2] / 16777216 +
|
||||||
|
bytes[offset + 3] / (255 * 16777216);
|
||||||
|
const screen = {
|
||||||
|
x: (canvasPixel[0] + 0.5) / scale,
|
||||||
|
y: (canvasPixel[1] + 0.5) / scale,
|
||||||
|
};
|
||||||
|
const ray = engine.camera.pickRay(screen);
|
||||||
|
const hit = engine.surface.raycast({ ...ray, far: view.camera.raw.far });
|
||||||
|
return {
|
||||||
|
pixel,
|
||||||
|
bindings: effect ? 'ground' : 'mrt',
|
||||||
|
allDepth: unpack(0),
|
||||||
|
sceneDepth: unpack(4),
|
||||||
|
globeDepth: unpack(8),
|
||||||
|
classification: ['none', 'terrain', 'tiles'][bytes[12]],
|
||||||
|
buffer: ['none', 'globe', 'scene'][bytes[12]],
|
||||||
|
position: hit?.position ?? engine.camera.pickEllipsoid(screen),
|
||||||
|
shownTileAtRay: Boolean(hit),
|
||||||
|
photorealActive: engine.maps.photorealActive(),
|
||||||
|
textures: textures.map((texture) => ({
|
||||||
|
id: texture.id,
|
||||||
|
width: texture.image.width,
|
||||||
|
height: texture.image.height,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
renderer.setRenderTarget(previous);
|
||||||
|
copy.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkPoints(page, kind) {
|
async function checkPoints(page, kind) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Cesium3DTileset } from 'cesium';
|
|||||||
import { Core, initSync } from '@navaramap/engine';
|
import { Core, initSync } from '@navaramap/engine';
|
||||||
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
||||||
import { Group, Raycaster, Vector3 } from 'three';
|
import { Group, Raycaster, Vector3 } from 'three';
|
||||||
|
import { DepthCopyPass } from 'postprocessing';
|
||||||
import * as geo from '../src/geo/index.js';
|
import * as geo from '../src/geo/index.js';
|
||||||
import { buildTilesFixture } from './build-tiles3d-fixture.mjs';
|
import { buildTilesFixture } from './build-tiles3d-fixture.mjs';
|
||||||
import { localTilesetPath, qaTilesetUrl } from '../src/maps/qaTileset.js';
|
import { localTilesetPath, qaTilesetUrl } from '../src/maps/qaTileset.js';
|
||||||
@@ -13,6 +14,7 @@ import { MapSourceController } from '../src/maps/controller.js';
|
|||||||
import { createFakeEngine } from '../src/globe/testing/fakeEngine.js';
|
import { createFakeEngine } from '../src/globe/testing/fakeEngine.js';
|
||||||
import { createNavaraMaps } from '../src/globe/navara/maps.js';
|
import { createNavaraMaps } from '../src/globe/navara/maps.js';
|
||||||
import { createNavaraSurface } from '../src/globe/navara/surface.js';
|
import { createNavaraSurface } from '../src/globe/navara/surface.js';
|
||||||
|
import { GROUND_SURFACE_GLSL } from '../src/globe/navara/ground/surface.js';
|
||||||
import {
|
import {
|
||||||
assertKeylessPreview,
|
assertKeylessPreview,
|
||||||
TILES_FIXTURE_PATH,
|
TILES_FIXTURE_PATH,
|
||||||
@@ -374,3 +376,227 @@ test('harness exposes exactly the five binary-safe fixture routes on the preview
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load only the page callbacks, without launching the command-line scenario.
|
||||||
|
const scenario = readFileSync(
|
||||||
|
new URL('./qa-tiles-fixture.mjs', import.meta.url),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
const diagnosticSource = scenario.slice(
|
||||||
|
scenario.indexOf('function readNavaraDrape('),
|
||||||
|
scenario.indexOf('async function checkPoints('),
|
||||||
|
);
|
||||||
|
const readNavaraDrape = new Function(`return (${diagnosticSource})`)();
|
||||||
|
const pixelsSource = scenario.slice(
|
||||||
|
scenario.indexOf('async function pixels('),
|
||||||
|
scenario.indexOf('// Runs in the page, after rendering.'),
|
||||||
|
);
|
||||||
|
const reportPixels = new Function(
|
||||||
|
'geo',
|
||||||
|
'report',
|
||||||
|
'readNavaraDrape',
|
||||||
|
'GROUND_SURFACE_GLSL',
|
||||||
|
`return (${pixelsSource})`,
|
||||||
|
)(geo, true, readNavaraDrape, GROUND_SURFACE_GLSL);
|
||||||
|
|
||||||
|
function depthDiagnostic(t) {
|
||||||
|
const copies = [];
|
||||||
|
class Copy extends DepthCopyPass {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.disposed = false;
|
||||||
|
this.renderTarget.addEventListener('dispose', () => {
|
||||||
|
this.disposed = true;
|
||||||
|
});
|
||||||
|
copies.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bytes = new Uint8Array(16);
|
||||||
|
// Exact RGBA depths: 0.25 composed, 0.25 scene, 0.5 globe; tile classification.
|
||||||
|
bytes.set([64, 0, 0, 0, 64, 0, 0, 0, 128, 0, 0, 0, 2, 0, 0, 255]);
|
||||||
|
let error = 0;
|
||||||
|
const gl = { NO_ERROR: 0, getError: () => error };
|
||||||
|
const textures = Array.from({ length: 3 }, (_, id) => ({
|
||||||
|
id,
|
||||||
|
image: { width: 1280, height: 800 },
|
||||||
|
}));
|
||||||
|
const previous = {};
|
||||||
|
const renderer = {
|
||||||
|
getContext: () => gl,
|
||||||
|
getRenderTarget: () => previous,
|
||||||
|
render: t.mock.fn(),
|
||||||
|
readRenderTargetPixels: (_, x, y, width, height, buffer) =>
|
||||||
|
buffer.set(bytes),
|
||||||
|
setRenderTarget: t.mock.fn(),
|
||||||
|
};
|
||||||
|
let effect = {
|
||||||
|
uniforms: new Map(
|
||||||
|
['tAllDepth', 'tSurfaceDepth', 'tGlobeDepth'].map((name, i) => [
|
||||||
|
name,
|
||||||
|
{ value: textures[i] },
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
getFragmentShader: () => GROUND_SURFACE_GLSL,
|
||||||
|
};
|
||||||
|
const ctx = {
|
||||||
|
getRenderer: () => renderer,
|
||||||
|
findEffect: (key) =>
|
||||||
|
key === 'gevGround'
|
||||||
|
? { effect }
|
||||||
|
: {
|
||||||
|
depthBuffer: textures[0],
|
||||||
|
globeDepthBuffer: textures[2],
|
||||||
|
raw: { globeDepthCopyPass: { constructor: Copy } },
|
||||||
|
},
|
||||||
|
getRenderTarget: () => ({ depthTexture: textures[1] }),
|
||||||
|
};
|
||||||
|
let tiles = true;
|
||||||
|
const position = geo.cartesian3.fromDegrees(-97.7, 30.2, 50);
|
||||||
|
let listener;
|
||||||
|
const engine = {
|
||||||
|
kind: 'navara',
|
||||||
|
extensions: {
|
||||||
|
navara: { view: { viewContext: ctx, camera: { raw: { far: 1e8 } } } },
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
canvas: { width: 2560, height: 1600 },
|
||||||
|
size: () => ({ width: 1280, height: 800 }),
|
||||||
|
},
|
||||||
|
projector: { worldToWindow: () => ({ x: 120, y: 70 }) },
|
||||||
|
camera: {
|
||||||
|
pickRay: t.mock.fn(() => ({
|
||||||
|
origin: { x: 1, y: 2, z: 3 },
|
||||||
|
direction: { x: 0, y: 0, z: -1 },
|
||||||
|
})),
|
||||||
|
pickEllipsoid: () => position,
|
||||||
|
},
|
||||||
|
surface: {
|
||||||
|
raycast: t.mock.fn(() => (tiles ? { position } : undefined)),
|
||||||
|
sampleHeightDetailed: t.mock.fn(() => ({
|
||||||
|
height: tiles ? 50 : 0,
|
||||||
|
source: tiles ? 'tiles' : 'terrain',
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
maps: { photorealActive: () => tiles },
|
||||||
|
frames: {
|
||||||
|
postRender: {
|
||||||
|
addEventListener: (fn) => {
|
||||||
|
listener = fn;
|
||||||
|
return () => {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render: { request: () => queueMicrotask(() => listener()) },
|
||||||
|
};
|
||||||
|
const color = Uint8ClampedArray.from(
|
||||||
|
{ length: 100 },
|
||||||
|
(_, i) => [231, 226, 223, 255][i % 4],
|
||||||
|
);
|
||||||
|
globals(t, {
|
||||||
|
window: { __godsEyeView: { engine } },
|
||||||
|
document: {
|
||||||
|
createElement: () => ({
|
||||||
|
getContext: () => ({
|
||||||
|
clearRect() {},
|
||||||
|
drawImage() {},
|
||||||
|
getImageData: () => ({ data: color }),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
engine,
|
||||||
|
copies,
|
||||||
|
renderer,
|
||||||
|
previous,
|
||||||
|
position,
|
||||||
|
textures,
|
||||||
|
page: { evaluate: async (fn, ...args) => fn(...args) },
|
||||||
|
hideGround() {
|
||||||
|
effect = null;
|
||||||
|
},
|
||||||
|
removeTiles() {
|
||||||
|
tiles = false;
|
||||||
|
bytes.set([128, 0, 0, 0, 255, 255, 255, 255, 128, 0, 0, 0, 1, 0, 0, 255]);
|
||||||
|
},
|
||||||
|
fail() {
|
||||||
|
error = 'INVALID_OPERATION';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('drape report distinguishes depths and shown tile rays when colour is identical', async (t) => {
|
||||||
|
const h = depthDiagnostic(t);
|
||||||
|
const shown = await reportPixels(h.page, h.position);
|
||||||
|
assert.deepEqual(shown.rgb, [231, 226, 223]);
|
||||||
|
assert.equal(shown.depths.allDepth, 0.25);
|
||||||
|
assert.equal(shown.depths.sceneDepth, 0.25);
|
||||||
|
assert.equal(shown.depths.globeDepth, 0.5);
|
||||||
|
assert.equal(shown.depths.buffer, 'scene');
|
||||||
|
assert.equal(shown.depths.classification, 'tiles');
|
||||||
|
assert.equal(shown.depths.source, 'tiles');
|
||||||
|
assert.equal(shown.depths.shownTileAtRay, true);
|
||||||
|
assert.equal(shown.depths.bindings, 'ground');
|
||||||
|
assert.deepEqual(shown.depths.pixel, [120, 729]);
|
||||||
|
assert.deepEqual(h.engine.camera.pickRay.mock.calls[0].arguments[0], {
|
||||||
|
x: 120.25,
|
||||||
|
y: 70.25,
|
||||||
|
});
|
||||||
|
assert.equal(h.engine.surface.raycast.mock.calls[0].arguments[0].far, 1e8);
|
||||||
|
const place =
|
||||||
|
h.engine.surface.sampleHeightDetailed.mock.calls[0].arguments[0];
|
||||||
|
assert.ok(Math.abs(place.longitude - geo.math.toRadians(-97.7)) < 1e-10);
|
||||||
|
assert.ok(Math.abs(place.latitude - geo.math.toRadians(30.2)) < 1e-10);
|
||||||
|
h.hideGround();
|
||||||
|
h.removeTiles();
|
||||||
|
const hidden = await reportPixels(h.page, h.position);
|
||||||
|
assert.deepEqual(hidden.rgb, shown.rgb);
|
||||||
|
assert.equal(hidden.depths.allDepth, 0.5);
|
||||||
|
assert.equal(hidden.depths.sceneDepth, 1);
|
||||||
|
assert.equal(hidden.depths.globeDepth, 0.5);
|
||||||
|
assert.equal(hidden.depths.buffer, 'globe');
|
||||||
|
assert.equal(hidden.depths.classification, 'terrain');
|
||||||
|
assert.equal(hidden.depths.source, 'terrain');
|
||||||
|
assert.equal(hidden.depths.shownTileAtRay, false);
|
||||||
|
assert.equal(hidden.depths.photorealActive, false);
|
||||||
|
assert.equal(hidden.depths.bindings, 'mrt');
|
||||||
|
assert.equal(h.copies.length, 4);
|
||||||
|
assert.ok(h.copies.every((copy) => copy.disposed));
|
||||||
|
assert.equal(
|
||||||
|
h.copies[0].fullscreenMaterial.uniforms.tGlobeDepth.value,
|
||||||
|
h.textures[2],
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
h.renderer.setRenderTarget.mock.calls.at(-1).arguments[0],
|
||||||
|
h.previous,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('drape report rejects a failed GPU read and releases temporary resources', async (t) => {
|
||||||
|
const h = depthDiagnostic(t);
|
||||||
|
h.fail();
|
||||||
|
await assert.rejects(
|
||||||
|
reportPixels(h.page, h.position),
|
||||||
|
/WebGL error: INVALID_OPERATION/,
|
||||||
|
);
|
||||||
|
assert.equal(h.copies.length, 1);
|
||||||
|
assert.ok(h.copies[0].disposed);
|
||||||
|
assert.equal(
|
||||||
|
h.renderer.setRenderTarget.mock.calls.at(-1).arguments[0],
|
||||||
|
h.previous,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('drape report never reads native Navara state on Cesium', async (t) => {
|
||||||
|
const h = depthDiagnostic(t);
|
||||||
|
h.engine.kind = 'cesium';
|
||||||
|
Object.defineProperty(h.engine, 'extensions', {
|
||||||
|
get() {
|
||||||
|
throw new Error('Native read');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const sample = await reportPixels(h.page, h.position);
|
||||||
|
assert.deepEqual(sample.rgb, [231, 226, 223]);
|
||||||
|
assert.equal(sample.depths, undefined);
|
||||||
|
assert.equal(h.copies.length, 0);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user