Skip to main content

FastModelPicker

GPU-readback picker that identifies what's under a screen position without going through the worker raycast.

Every query goes through renderPick: one render of the BIM scene into a 1×1 multiple-render-target, through a camera whose frustum covers only the pixel under the cursor. The pick shader writes the item id, depth and normal of that pixel into one attachment each, so they always describe the same fragment; each query reads back only the attachments it needs.

What can be picked is what is drawn. An item that fragments currently draws at a reduced LOD — a line mesh carrying no id attribute — is not pickable, and the pick resolves to whatever is behind it; the worker raycast tests the authored geometry instead, so the two can disagree on small or distant items, see collectPickables.

Item id encoding (one pixel). The id is written as itemId + 1 so that an unwritten pixel (all zeroes) decodes as "no item" rather than item 0: R = modelByte (1..254, 0 = void / unwritten) G = ((itemId + 1) >> 16) & 0xff B = ((itemId + 1) >> 8) & 0xff A = (itemId + 1) & 0xff

modelByte is assigned per-pick, so the assignment is stable for the duration of the pick but doesn't grow over the session.

Implements​

Properties​

components​

components: Components

Components instance this picker belongs to.


debugMode​

debugMode: boolean = false

When true, mirrors the id output of the whole viewport to a debug canvas pinned in the top-right corner. Each model shows up as a near-uniform red band (the model byte) modulated by varying greens / blues from the per-item id encoding.


enabled​

enabled: boolean = true

Component.enabled


mouse​

readonly mouse: Mouse

Position helper bound to the world's canvas.


onDisposed​

readonly onDisposed: Event<unknown>

Disposable.onDisposed

Implementation of​

Disposable . onDisposed


world​

world: World

World this picker renders against.


MAX_MODELS​

static readonly MAX_MODELS: 254 = 254

Maximum models the picker can disambiguate in a single pick. Capped by the 8-bit modelByte. In practice we never approach this.

Methods​

dispose()​

dispose(): void

Disposable.dispose

Returns​

void

Implementation of​

Disposable . dispose


getFullPick()​

getFullPick(position?): Promise<null | object>

One-shot pick that produces the full result shape consumers need: { modelId, localId, point, normal, distance }, all from the same render.

Returns null if the cursor is over empty space, the id output decodes to the void sentinel, or the depth round-trip yields the far plane.

Parameters​

ParameterType
position?Vector2

Returns​

Promise<null | object>


getItemAt()​

getItemAt(position?): Promise<null | object>

Returns { modelId, localId } for the item under the given screen position, or null if the cursor is over empty space.

The vertex id attribute encodes the internal itemId (the FlatBuffer sample.item() index, key for boxes.sampleOf) rather than the user-facing localId, which unblocks the snap path's O(1) sample lookup. The trade-off: resolving localId takes one worker round-trip. Internal consumers that only need itemId (e.g. snap) can read it from the result directly.

Parameters​

ParameterTypeDescription
position?Vector2

Normalized device coords. Defaults to the

picker's last known mouse position.

Returns​

Promise<null | object>


getModelAt()​

getModelAt(position?): Promise<null | string>

Returns the model id under the given screen position, or null if the cursor is over empty space.

Cheaper than getItemAt because we don't resolve the localId; we just read the model byte.

Parameters​

ParameterTypeDescription
position?Vector2

Normalized device coords. Defaults to the

picker's last known mouse position.

Returns​

Promise<null | string>


getNormalAt()​

getNormalAt(position?): Promise<null | Vector3>

Returns the world-space surface normal under the cursor, or null if the cursor is over empty space.

Parameters​

ParameterTypeDescription
position?Vector2

Normalized device coords. Defaults to the

picker's last known mouse position.

Returns​

Promise<null | Vector3>


getPointAt()​

getPointAt(position?): Promise<null | Vector3>

Returns the world-space point under the given screen position, or null if the cursor is over empty space.

Reads the packed gl_FragCoord.z of the picked pixel and unprojects it through the pick camera. Useful for things like "set camera orbit center to what the user just clicked on".

Parameters​

ParameterTypeDescription
position?Vector2

Normalized device coords. Defaults to the

picker's last known mouse position.

Returns​

Promise<null | Vector3>


setDebugMode()​

setDebugMode(enabled): void

Toggle the debug overlay. When enabled the picker mirrors the id output of the whole viewport to a small canvas pinned in the top-right corner so you can see what the picks see.

Parameters​

ParameterType
enabledboolean

Returns​

void