fix: use whole-anchor occlusion for BGP icons
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled

This commit is contained in:
rayd1o
2026-09-30 22:59:21 +08:00
parent 96e9b15fda
commit 06c122bade
3 changed files with 24 additions and 1 deletions

View File

@@ -282,6 +282,7 @@ const bgpEventIconLayer = createInteractableLayer({
coordinates: "canvas",
draw: drawBGPEventIcon,
},
surfaceAnchorOcclusion: true,
getPosition: (item) => ({
latitude: item.latitude,
longitude: item.longitude,

View File

@@ -490,6 +490,7 @@ export function createInteractableLayer(options = {}) {
avoidance = false,
cluster = undefined,
icon,
surfaceAnchorOcclusion = false,
getPosition,
getKind = (item) => item?.type || "default",
getRotationBin = () => 0,
@@ -548,7 +549,9 @@ export function createInteractableLayer(options = {}) {
const hoverScale = stateScale.hover ?? 1;
const lockedScale = stateScale.locked ?? 1;
const dimmedScale = stateScale.dimmed ?? 1;
const usesSurfaceAnchorOcclusion = Boolean(icon.badge);
// Rounded badges enable this implicitly, while other icon styles can opt
// into the same whole-billboard surface behavior without changing artwork.
const usesSurfaceAnchorOcclusion = Boolean(surfaceAnchorOcclusion || icon.badge);
const depthTest = usesSurfaceAnchorOcclusion ? false : material.depthTest ?? true;
const depthWrite = material.depthWrite ?? false;
const alphaTest = material.alphaTest ?? 0.01;

View File

@@ -82,6 +82,25 @@ test('projected BGP symbols bake the same category color as GPU vertex colors',
} finally {layer?.clearData();globalThis.document=oldDocument;globalThis.window=oldWindow;}
});
test('surface anchor occlusion can preserve a custom icon drawing style', () => {
const oldDocument = globalThis.document, oldWindow = globalThis.window;
globalThis.window = { innerWidth: 1280, innerHeight: 720, devicePixelRatio: 1 };
globalThis.document = { createElement: () => ({ width: 128, height: 128, getContext: () => new Proxy({}, { get: () => () => {} }) }) };
let layer;
try {
layer = createInteractableLayer({ id: 'surface-anchor-style-test', cluster: false,
surfaceAnchorOcclusion: true, getPosition: item => item,
icon: { draw() {} } });
const earth = new THREE.Object3D(), camera = new THREE.PerspectiveCamera(75, 1, .1, 5000);
camera.position.z = 350; camera.updateMatrixWorld();
layer.attach(earth); layer.setVisible(true); layer.setData([{ id: 'custom', latitude: 0, longitude: -90 }]);
layer.updateVisualState(null, null, camera);
const points = layer.group.children.find(group => group.children.some(child => child.isPoints)).children.find(child => child.isPoints);
expect(points.material.depthTest).toBe(false);
expect(points.material.defines.USE_SURFACE_ANCHOR_OCCLUSION).toBe('');
} finally { layer?.clearData(); globalThis.document = oldDocument; globalThis.window = oldWindow; }
});
test('selected pulses do not refresh unchanged batches; state changes still do', () => {
const oldDocument=globalThis.document,oldWindow=globalThis.window;