From 3e30a221d0f419cc524c87898c42c85616d9563a Mon Sep 17 00:00:00 2001 From: Marco Muser Date: Mon, 25 May 2026 15:13:11 +0200 Subject: [PATCH 1/3] fix: include terrainLayers in offset mode --- modules/core/src/lib/deck-picker.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/core/src/lib/deck-picker.ts b/modules/core/src/lib/deck-picker.ts index 5b48426c930..5b7671d187e 100644 --- a/modules/core/src/lib/deck-picker.ts +++ b/modules/core/src/lib/deck-picker.ts @@ -1027,7 +1027,10 @@ export default class DeckPicker { /** * Determine which layers to use for the depth (pickZ) pass. - * - If a non-draped layer was picked, use just that layer. + * - If a non-terrain-dependent layer was picked, use just that layer. + * - If an offset layer was picked, include terrain layers alongside it so + * TerrainEffect.preRender can bind the heightmap and the layer renders at + * its correct elevation (terrain_z + data_z). * - If a draped layer was picked (geometry is at z=0) or no layer was picked * (e.g. no-FBO tiles at extreme zoom), fall back to terrain layers. */ @@ -1036,12 +1039,19 @@ export default class DeckPicker { return []; } const {pickedLayer} = pickInfo; - const isDraped = pickedLayer?.state?.terrainDrawMode === 'drape'; - if (pickedLayer && !isDraped) { + const terrainLayers = pickableLayers.filter(l => l.props.operation.includes('terrain')); + const terrainDrawMode = pickedLayer?.state?.terrainDrawMode; + if (pickedLayer && terrainDrawMode === 'offset') { + // Terrain layers must be included so TerrainEffect.preRender doesn't early-exit, + // allowing the heightmap to be bound and the offset layer to render at its correct + // elevation (terrain_z + data_z). + return [pickedLayer, ...terrainLayers]; + } + if (pickedLayer && terrainDrawMode !== 'drape') { return [pickedLayer]; } // For draped layers or when no layer was picked, use terrain layers for depth - return pickableLayers.filter(l => l.props.operation.includes('terrain')); + return terrainLayers; } /** From ff95d35940a52975f38b89186b3e0644cef836d7 Mon Sep 17 00:00:00 2001 From: Marco Muser Date: Mon, 25 May 2026 15:24:23 +0200 Subject: [PATCH 2/3] docs: simplify code comment --- modules/core/src/lib/deck-picker.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/core/src/lib/deck-picker.ts b/modules/core/src/lib/deck-picker.ts index 5b7671d187e..2becc89de80 100644 --- a/modules/core/src/lib/deck-picker.ts +++ b/modules/core/src/lib/deck-picker.ts @@ -1042,9 +1042,7 @@ export default class DeckPicker { const terrainLayers = pickableLayers.filter(l => l.props.operation.includes('terrain')); const terrainDrawMode = pickedLayer?.state?.terrainDrawMode; if (pickedLayer && terrainDrawMode === 'offset') { - // Terrain layers must be included so TerrainEffect.preRender doesn't early-exit, - // allowing the heightmap to be bound and the offset layer to render at its correct - // elevation (terrain_z + data_z). + // For offset layers, include terrain layers alongside return [pickedLayer, ...terrainLayers]; } if (pickedLayer && terrainDrawMode !== 'drape') { From d16a00d4c0ef582a4d6adc2568331fee3e56341a Mon Sep 17 00:00:00 2001 From: Marco Muser Date: Mon, 25 May 2026 15:25:15 +0200 Subject: [PATCH 3/3] test: _getDepthLayers --- test/modules/core/lib/deck-picker.spec.ts | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/modules/core/lib/deck-picker.spec.ts b/test/modules/core/lib/deck-picker.spec.ts index 35be9e3bd79..6ab9f367b0d 100644 --- a/test/modules/core/lib/deck-picker.spec.ts +++ b/test/modules/core/lib/deck-picker.spec.ts @@ -147,3 +147,41 @@ test('DeckPicker#pick async empty', async () => { layerManager.finalize(); deckPicker.finalize(); }); + +test('DeckPicker#getDepthLayers', () => { + const deckPicker = new DeckPicker(device); + // depthFBO must exist or the method early-returns [] + deckPicker.depthFBO = {destroy: () => {}}; + + const terrainLayer = {props: {operation: 'terrain+draw'}, state: {}}; + const offsetLayer = {props: {operation: 'draw'}, state: {terrainDrawMode: 'offset'}}; + const drapedLayer = {props: {operation: 'draw'}, state: {terrainDrawMode: 'drape'}}; + const regularLayer = {props: {operation: 'draw'}, state: {}}; + + const pickableLayers = [offsetLayer, terrainLayer, regularLayer, drapedLayer]; + const noPick = {pickedColor: null, pickedObjectIndex: -1}; + + // unproject3D disabled → always [] + expect(deckPicker._getDepthLayers(noPick, pickableLayers, false)).toEqual([]); + + // nothing picked → terrain layers + expect(deckPicker._getDepthLayers(noPick, pickableLayers, true)).toEqual([terrainLayer]); + + // regular layer picked → just that layer + expect( + deckPicker._getDepthLayers({...noPick, pickedLayer: regularLayer}, pickableLayers, true) + ).toEqual([regularLayer]); + + // drape layer picked → terrain layers (geometry is at z=0, need terrain for depth) + expect( + deckPicker._getDepthLayers({...noPick, pickedLayer: drapedLayer}, pickableLayers, true) + ).toEqual([terrainLayer]); + + // offset layer picked → [pickedLayer, ...terrainLayers] so TerrainEffect.preRender + // doesn't early-exit and the heightmap is available for the depth pass + expect( + deckPicker._getDepthLayers({...noPick, pickedLayer: offsetLayer}, pickableLayers, true) + ).toEqual([offsetLayer, terrainLayer]); + + deckPicker.finalize(); +});