Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/api-reference/core/deck.md
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ Parameters:
* `y` (number) - y position in pixels
* `radius` (number, optional) - radius of tolerance in pixels. Default `0`.
* `layerIds` (string[], optional) - a list of layer ids to query from. If not specified, then all pickable and visible layers are queried.
* `depth` - Specifies the max number of objects to return. Default `10`.
* `depth` - Specifies the max number of objects to return. Default `10`. For layers without explicit picking color buffers, only the default depth of 10 unique objects per layer is guaranteed; higher custom depths may return duplicate results for these layers.
* `unproject3D` (boolean, optional) - if `true`, `info.coordinate` will be a 3D point by unprojecting the `x, y` screen coordinates onto the picked geometry. Default `false`.

Returns:
Expand All @@ -783,6 +783,7 @@ Returns:
Notes:

* Deep picking is implemented as a sequence of simpler picking operations and can have a performance impact. Should this become a concern, you can use the `depth` parameter to limit the number of matches that can be returned, and thus the maximum number of picking operations.
* Layers that provide explicit picking color buffers support buffer mutation between picking passes and are not subject to the default-depth unique-object guarantee.


#### `pickObjects` {#pickobjects}
Expand Down
5 changes: 3 additions & 2 deletions docs/api-reference/core/globe-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ new Deck({
Supports all [Controller options](./controller.md#options) with the following default behavior:

- `dragPan`: default `'pan'` (drag to pan)
- `dragRotate`: not effective, this view does not currently support rotation
- `touchRotate`: not effective, this view does not currently support rotation
- `dragRotate`: shift+drag or right-click drag to change bearing and pitch
- `touchRotate`: multi-touch rotate to change bearing
- `keyboard`: arrow keys to pan, +/- to zoom
- `inertia`: when set to a number (milliseconds), the globe continues spinning after a fling gesture with exponential decay
- `maxBounds` - constrains the viewport to the specified bounding box `[[minLng, minLat], [maxLng, maxLat]]`

## Custom GlobeController
Expand Down
8 changes: 6 additions & 2 deletions docs/api-reference/core/globe-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ It's recommended that you read the [Views and Projections guide](../../developer
## Limitations

The goal of `GlobeView` is to provide a generic solution to rendering and navigating data in the 3D space.
In the initial release, this class mainly addresses the need to render an overview of the entire globe. The following limitations apply, as features are still under development:

- No support for rotation (`pitch` or `bearing`). The camera always points towards the center of the earth, with north up.
- No high-precision rendering at high zoom levels (> 12). Features at the city-block scale may not be rendered accurately.
- Only supports `'lnglat'` (the default value of the `coordinateSystem` prop).
- Known rendering issues when using multiple views mixing `GlobeView` and `MapView`, or switching between the two.
Expand Down Expand Up @@ -72,8 +70,14 @@ To render, `GlobeView` needs to be used together with a `viewState` with the fol
- `longitude` (number) - longitude at the viewport center
- `latitude` (number) - latitude at the viewport center
- `zoom` (number) - zoom level
- `bearing` (number, optional) - bearing angle in degrees. Default `0` (north up).
- `pitch` (number, optional) - pitch angle in degrees. `0` looks straight down at the earth. Default `0`.
- `maxZoom` (number, optional) - max zoom level. Default `20`.
- `minZoom` (number, optional) - min zoom level. Default `0`.
- `maxPitch` (number, optional) - max pitch angle. Default `60`.
- `minPitch` (number, optional) - min pitch angle. Default `0`.

When `bearing` is `0` (the default), north is always kept pointing up and the globe behaves like a traditional desk globe — horizontal drag changes longitude, vertical drag changes latitude, and the polar axis stays fixed. When the user changes the bearing (via shift+drag or right-click drag), the globe enters free rotation mode where bearing evolves naturally to avoid orientation discontinuities near the poles.


## Controller
Expand Down
8 changes: 5 additions & 3 deletions docs/api-reference/core/globe-viewport.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GlobeViewport (Experimental)

The `GlobeViewport` class takes globe view states (`latitude`, `longitude`, and `zoom`), and performs projections between world and screen coordinates. It is a helper class for visualizing the earth as a 3D globe.
The `GlobeViewport` class takes globe view states (`latitude`, `longitude`, `zoom`, `bearing`, and `pitch`), and performs projections between world and screen coordinates. It is a helper class for visualizing the earth as a 3D globe.

## Usage

Expand All @@ -25,7 +25,7 @@ viewport.project([-122.45, 37.78]);
## Constructor

```js
new GlobeViewport({width, height, longitude, latitude, zoom});
new GlobeViewport({width, height, longitude, latitude, zoom, bearing, pitch});
```

Parameters:
Expand All @@ -40,11 +40,13 @@ Parameters:
+ `latitude` (number, optional) - Latitude of the viewport center on map. Default to `0`.
+ `longitude` (number, optional) - Longitude of the viewport center on map. Default to `0`.
+ `zoom` (number, optional) - Map zoom (scale is calculated as `2^zoom`). Default to `11`.
+ `bearing` (number, optional) - Bearing angle in degrees. Default to `0`.
+ `pitch` (number, optional) - Pitch angle in degrees. Default to `0`.
+ `altitude` (number, optional) - Altitude of camera, 1 unit equals to the height of the viewport. Default to `1.5`.

projection matrix arguments:

+ `nearZMultiplier` (number, optional) - Scaler for the near plane, 1 unit equals to the height of the viewport. Default to `0.1`.
+ `nearZMultiplier` (number, optional) - Scaler for the near plane, 1 unit equals to the height of the viewport. Default to `0.01`.
+ `farZMultiplier` (number, optional) - Scaler for the far plane, 1 unit equals to the distance from the camera to the top edge of the screen. Default to `1`.

Remarks:
Expand Down
2 changes: 1 addition & 1 deletion docs/developer-guide/custom-layers/attribute-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ While most apps rely on their layers to automatically generate appropriate GPU b

While this allows for ultimate performance and control of updates, as well as potential sharing of buffers between layers, the application will need to generate attributes in exactly the format that the layer shaders expect, creating a strong coupling between the application and the layer.

**Note:** The application can provide some buffers and let others be managed by the layer. As an example management of the `instancePickingColors` buffer is normally left to the layer.
**Note:** The application can provide some buffers and let others be managed by the layer. Explicit picking color buffers are only needed when the logical picking id differs from the rendered instance id.


## More information
Expand Down
12 changes: 11 additions & 1 deletion docs/developer-guide/custom-layers/picking.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,17 @@ When other gestures (click, drag, etc.) are detected, deck.gl does not repeat pi
special support is provided for the built-in "picking color" based picking
system, which most layers use.

To take full control of picking, a layer need to take the following steps:
The following sections describe common ways to implement custom picking.

### Default Instanced Picking

Instanced layer shaders can derive picking colors from the built-in instance id when each rendered instance maps to one picked object. In GLSL, use `picking_setPickingColorFromInstanceID()` or assign `geometry.pickingColor = picking_getPickingColorFromInstanceID()`. In WGSL, add `@builtin(instance_index)` to the vertex inputs and use `picking_getPickingColorFromIndex(instanceIndex)`.

Add an explicit picking color attribute only when the logical picking id within the current layer is different from the rendered instance id. For example:

* Binary GeoJSON or MVT point sublayers may render local point instances while picking should return a global feature index.

* `PathLayer` tessellates one path into multiple rendered segment or joint instances, so its generated geometry needs explicit picking colors that map back to the source path index instead of each rendered segment's instance id.

### Creating A Picking Color Attribute

Expand Down
4 changes: 1 addition & 3 deletions docs/developer-guide/custom-layers/primitive-layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,4 @@ By always using the following shader functions for handling projections and scal

If your layer is instanced (`data` prop is an array and each element is rendered as one primitive), then you may take advantage of the default implementation of the [layer picking methods](../../api-reference/core/layer.md#layer-picking-methods).

By default, each layer creates an `instancePickingColors` attribute and automatically calculates it using the length of the `data` array.

For custom picking, read about [Implementing Custom Picking](./picking.md#implementing-custom-picking).
By default, instanced layer shaders can derive picking colors from the built-in instance id. Add an explicit picking color attribute only when the logical picking id within the current layer is different from the rendered instance id. See [Implementing Custom Picking](./picking.md#implementing-custom-picking) for custom picking details and examples.
3 changes: 1 addition & 2 deletions docs/developer-guide/custom-layers/subclassed-layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ attribute vec3 instanceNormals;
attribute vec4 instanceColors;
attribute vec3 instancePositions;
attribute vec3 instancePositions64Low;
attribute vec3 instancePickingColors;

/* New attribute */
attribute flat instanceRadiusPixels;
Expand All @@ -228,7 +227,7 @@ void main(void) {

vColor = vec4(lightColor, instanceColors.a * opacity) / 255.0;

picking_setPickingColor(instancePickingColors);
picking_setPickingColorFromInstanceID();
}
`;
```
Expand Down
15 changes: 15 additions & 0 deletions docs/upgrade-guide.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Upgrade Guide

## Upgrading to v9.4

#### `pickMultipleObjects()` pick depth limits

For layers that use built-in shader instance ids instead of explicit picking color buffers, `pickMultipleObjects()` now only guarantees the default `depth` of 10 unique objects per layer. Applications that call `pickMultipleObjects()` with a custom `depth` above the default may receive duplicate results for these layers. Layers with explicit picking color buffers keep their previous buffer-mutation behavior.

### `instancePickingColors` attribute is no longer automatically generated

Most built-in and custom instanced layers now derive picking colors from built-in shader instance ids, meaning the default `instancePickingColors` attribute is no longer automatically generated by deck.gl.

In rare cases, custom WebGL layer shaders may need an update if they explicitly read the `instancePickingColors` attribute.

- In such cases, use the new picking shader helper functions to derive the color from the instance id, for example `picking_setPickingColorFromInstanceID()` in GLSL or `picking_getPickingColorFromIndex(instanceIndex)` in WGSL.
- However, if the logical picking id is different from the rendered instance id, layers can still continue to register and populate an explicit picking color attribute as before.

## Upgrading to v9.3

Upgraded dependencies to [luma.gl v9.3](https://luma.gl/docs/upgrade-guide) and [loaders.gl v4.4](https://loaders.gl/docs/upgrade-guide). Your app may be affected if it contains custom layers.
Expand Down
4 changes: 4 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ This page contains highlights of each deck.gl release. Also check our [vis.gl bl

- Views now support a `parameters` prop for per-view GPU draw state overrides. `GlobeView` uses this to enable back-face culling by default, and applications can override it with `new GlobeView({parameters: {cullMode: 'none'}})`.

### Performance

- Picking in most instanced layers no longer allocates an `instancePickingColors` attribute buffer, instead using shader builtins `instance_index` / `gl_InstanceID`, reducing memory usage and initialization times.

## deck.gl v9.3

Release date: April 13, 2026
Expand Down
43 changes: 36 additions & 7 deletions examples/website/google-3d-tiles/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import React, {useState} from 'react';
import React, {useState, useMemo} from 'react';
import {scaleLinear} from 'd3-scale';
import {createRoot} from 'react-dom/client';
import {DeckGL} from '@deck.gl/react';
import {TerrainController} from '@deck.gl/core';
import {MapView, _GlobeView as GlobeView, TerrainController} from '@deck.gl/core';
import {GeoJsonLayer} from '@deck.gl/layers';
import {Tile3DLayer} from '@deck.gl/geo-layers';
import {DataFilterExtension, _TerrainExtension as TerrainExtension} from '@deck.gl/extensions';
Expand All @@ -28,10 +28,10 @@ const INITIAL_VIEW_STATE = {
latitude: 50.089,
longitude: 14.42,
zoom: 16,
minZoom: 14,
maxZoom: 18,
bearing: 90,
pitch: 60
minZoom: 0,
maxZoom: 24,
bearing: 0,
pitch: 0
};

const BUILDING_DATA =
Expand All @@ -50,6 +50,8 @@ function getTooltip({object}) {

export default function App({data = TILESET_URL, distance = 0, opacity = 0.2}) {
const [credits, setCredits] = useState('');
const [useGlobe, setUseGlobe] = useState(false);

const onTraversalComplete = selectedTiles => {
const uniqueCredits = new Set();
selectedTiles.forEach(tile => {
Expand Down Expand Up @@ -90,15 +92,42 @@ export default function App({data = TILESET_URL, distance = 0, opacity = 0.2}) {
})
];

const view = useMemo(
() =>
useGlobe
? new GlobeView({id: 'view', controller: true})
: new MapView({
id: 'view',
controller: {type: TerrainController, touchRotate: true, inertia: 500}
}),
[useGlobe]
);

return (
<div>
<DeckGL
key={useGlobe ? 'globe' : 'map'}
style={{backgroundColor: '#061714'}}
views={view}
initialViewState={INITIAL_VIEW_STATE}
controller={{type: TerrainController, touchRotate: true, inertia: 500}}
layers={layers}
getTooltip={getTooltip}
/>
<button
onClick={() => setUseGlobe(v => !v)}
style={{
position: 'absolute',
top: '8px',
left: '8px',
padding: '6px 10px',
fontFamily: 'sans-serif',
fontSize: '12px',
border: 'none',
cursor: 'pointer'
}}
>
{useGlobe ? 'Map' : 'Globe'}
</button>
<div
style={{position: 'absolute', left: '8px', bottom: '4px', color: 'white', fontSize: '10px'}}
>
Expand Down
4 changes: 1 addition & 3 deletions modules/aggregation-layers/src/common/aggregation-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ export default abstract class AggregationLayer<
/** Called when some attributes change, a chance to mark Aggregator as dirty */
abstract onAttributeChange(id: string): void;

initializeState(): void {
this.getAttributeManager()!.remove(['instancePickingColors']);
}
initializeState(): void {}

// Extend Layer.updateState to update the Aggregator instance
// returns true if aggregator is changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ in vec3 normals;
in vec2 instancePositions;
in float instanceElevationValues;
in float instanceColorValues;
in vec3 instancePickingColors;

uniform sampler2D colorRange;

Expand All @@ -30,7 +29,7 @@ vec4 interp(float value, vec2 domain, sampler2D range) {
}

void main(void) {
geometry.pickingColor = instancePickingColors;
geometry.pickingColor = picking_getPickingColorFromInstanceID();

if (isnan(instanceColorValues) ||
instanceColorValues < grid.colorDomain.z ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ in vec3 normals;
in vec2 instancePositions;
in float instanceElevationValues;
in float instanceColorValues;
in vec3 instancePickingColors;

uniform sampler2D colorRange;

Expand All @@ -34,7 +33,7 @@ vec4 interp(float value, vec2 domain, sampler2D range) {
}

void main(void) {
geometry.pickingColor = instancePickingColors;
geometry.pickingColor = picking_getPickingColorFromInstanceID();

if (isnan(instanceColorValues) ||
instanceColorValues < hexagon.colorDomain.z ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default /* glsl */ `\
in vec2 positions;
in vec2 instancePositions;
in float instanceWeights;
in vec3 instancePickingColors;

uniform sampler2D colorRange;

Expand All @@ -37,6 +36,6 @@ void main(void) {
vColor.a *= layer.opacity;

// Set color to be rendered to picking fbo (also used to check for selection highlight).
picking_setPickingColor(instancePickingColors);
picking_setPickingColorFromInstanceID();
}
`;
Loading
Loading