Skip to content

FG-13915: Fix scale-invariant label picking#455

Closed
niels-foxglove wants to merge 1 commit into
mainfrom
nn4/fg-13915
Closed

FG-13915: Fix scale-invariant label picking#455
niels-foxglove wants to merge 1 commit into
mainfrom
nn4/fg-13915

Conversation

@niels-foxglove

Copy link
Copy Markdown

Changelog

Fixed scale-invariant billboard text labels not being pickable in the 3D panel.

Docs

None

Description

Fixes: FG-13915

Problem: Billboard text labels with scale_invariant=true (sizeAttenuation=false in three-text) were not clickable in the 3D panel's select mode. The Picker renders objects into a small offscreen target using camera.setViewOffset() to zoom into the area around the cursor, then reads back pixel colors to determine what was clicked. The sizeAttenuation=false vertex shader path added offsets in clip space (after projection), which produces incorrect positions when setViewOffset modifies the projection matrix.

Solution: Move the sizeAttenuation=false offset calculation from clip space to view space (before projection). Multiply by camera distance (-mvPosition.z) to compensate for perspective divide, maintaining constant pixel size. This approach is compatible with setViewOffset because the projection matrix is applied after the offset.

Before (clip-space offset, broken with setViewOffset):

gl_Position = projectionMatrix * mvPosition;
// Add position after projection to maintain constant pixel size

After (view-space offset, works with setViewOffset):

// Add offset in view space before projection so that setViewOffset
// (used by the Picker) works correctly. Multiplying by distance
// compensates for the perspective divide, keeping constant pixel size.
float dist = -mvPosition.z;
mvPosition.xy += vertexPos * 2. * dist / resolution * scale;
gl_Position = projectionMatrix * mvPosition;

Also renamed uCanvasSize uniform to resolution (Three.js convention) and changed its type from [0, 0] array to THREE.Vector2(1, 1) to use .copy() in onBeforeRender.

Testing: Verified with a test data server that publishes a 3D scene with both scale_invariant=true and scale_invariant=false labels. Confirmed:

  • Before fix: only green (scale_invariant=false) labels pickable
  • After fix: both green and yellow (scale_invariant=true) labels pickable
  • Reverted to main and re-verified the bug returns

Note: This PR should be merged after #448 (WebGPU support) lands, then the app's Picker.ts resolution override (lines 297-302) should also be removed in a follow-up.

@linear

linear Bot commented Feb 13, 2026

Copy link
Copy Markdown

Move the sizeAttenuation=false vertex offset from clip space to view
space so that setViewOffset (used by the Picker) works correctly.
Multiply by camera distance to maintain constant pixel size.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@niels-foxglove

Copy link
Copy Markdown
Author

I will come back to this. This has been a low priority bug that nobody has reported yet and this PR is a draft because its only an AI generated first attempt. I will create a real PR when I've done a review of the code myself to get a better understanding of what is going on.

@jtbandes
jtbandes deleted the nn4/fg-13915 branch June 11, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant