I render many point markers in a Three.js scene. Some markers are custom 2D symbols made of lines, circles and filled shapes. They are drawn in screen-like size, so their visual size should stay usable while zooming.
Current picking:
meshes: Raycaster
lines/arcs: project endpoints to screen space, then test mouse distance to 2D segments
point markers: project marker center to screen space and use a pixel radius
Problem:
The radius-based marker picking is too rough. Some markers are hollow or only outlines, so I want the marker to be picked when the mouse is close to the actually visible stroke/fill, not just the center.
Requirements:
zoom-independent tolerance in pixels
works for custom marker shapes
clicking near a visible stroke should select it
clicking empty space should not select it
should work with many markers
What is the best technical approach in Three.js?
Options I’m considering:
custom CPU-side 2D hit testing against projected marker primitives
render an offscreen ID/color picking buffer
approximate each marker with simpler hit shapes
use instanced geometry and somehow derive picking from that
Which approach is usually best for this kind of screen-space marker picking?
have you considered using sprites with a transparent texture for the objects? this way you’d have a padding to the clickable area depending on the sprite / texture size ratio… or do the objects need to be rotatable in space relative to the camera?
Yes, I considered sprites, and they would work well for simple icon-like markers.
In my case the markers are CAD/survey-style symbols made from vector primitives: lines, arcs/circles, fills and sometimes text. They may have their own 2D symbol rotation, but they do not need arbitrary 3D rotation relative to the camera. They are mostly meant to behave like screen-facing / screen-sized CAD symbols.
The main issue with sprites is picking accuracy. Three.js raycasting against a Sprite would still hit the sprite quad, not the visible non-transparent pixels. So a transparent texture with padding would help tune the clickable area, but hollow symbols or outline-only symbols would still be selectable in empty areas unless I also do alpha-aware picking.
So for this use case I’m leaning toward either:
CPU-side 2D hit testing against the actual symbol primitives, after a coarse screen-space bounding-box / spatial-index filter, or
an offscreen ID picking pass where the same symbol shape is rendered with alpha/discard, so only visible pixels count.
If I converted the symbols to cached sprite textures, I’d probably still need alpha-based picking or an ID buffer to avoid selecting transparent parts.what would you recommend?