From 0df0fb82616abbf6b9f1fdff1b3ef3cded473519 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 20:41:13 +0400 Subject: [PATCH] fix(navara): separate always-visible shader programs --- src/globe/navara/movers/moverMesh.js | 2 +- src/globe/navara/movers/moverMesh.test.mjs | 28 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/globe/navara/movers/moverMesh.js b/src/globe/navara/movers/moverMesh.js index 034b330d1..1822cf3a6 100644 --- a/src/globe/navara/movers/moverMesh.js +++ b/src/globe/navara/movers/moverMesh.js @@ -309,7 +309,7 @@ export function createMoverMesh( alwaysVisible: depthTest === 'always', }); material.customProgramCacheKey = () => - `gev-mover-${kind}${encodedAtlas ? '-encoded-atlas' : ''}`; + `gev-mover-${kind}${encodedAtlas ? '-encoded-atlas' : ''}${depthTest === 'always' ? '-always-visible' : ''}`; const mesh = new InstancedMesh(geometry, material, capacity); mesh.userData.gevStaticSprite = kind === 'sprite' && diff --git a/src/globe/navara/movers/moverMesh.test.mjs b/src/globe/navara/movers/moverMesh.test.mjs index 52661fe33..510d5d708 100644 --- a/src/globe/navara/movers/moverMesh.test.mjs +++ b/src/globe/navara/movers/moverMesh.test.mjs @@ -29,6 +29,34 @@ const basicShader = () => ({ fragmentShader: ShaderLib.basic.fragmentShader, }); +test('depth-tested and always-visible movers cannot reuse incompatible shader programs', () => { + for (const kind of ['point', 'sprite']) { + const movers = ['normal', 'always', { disableWithinM: 2000 }].map( + (depthTest) => { + const options = normalizeMoverSetOptions({ + ...spriteOptions, + kind, + depthTest, + point: { sizePx: 8 }, + }); + return createMoverMesh(options, createMoverStore(options)); + }, + ); + const keys = movers.map((m) => m.mesh.material.customProgramCacheKey()); + assert.notEqual( + keys[0], + keys[1], + `${kind}: different depth GLSL requires different programs`, + ); + assert.equal( + keys[0], + keys[2], + `${kind}: distance escape is a uniform, not another program`, + ); + for (const mover of movers) mover.dispose(); + } +}); + test('point translucency applies to fill and outline and defaults to no fade', () => { const options = normalizeMoverSetOptions({ id: 'stations',