Tests the picking ray through (ndcX, ndcY) against every candidate and
returns the hits, nearest first (§71).
consthits: PickHit[] = []; // reused pick(camera, ndcX, ndcY, pickables, hits); if (hits.length > 0) select(hits[0].node); // hits[0] is the front-most
Each candidate is tested in its own local space — the ray is transformed
by the inverse of the node's world matrix, so a rotated or non-uniformly
scaled box is tested exactly rather than as an inflated world-space AABB (see
the module header). World matrices are resolved on demand per candidate, so
the result is correct mid-frame without a preceding resolve pass.
Every hit reports the entry point: the first intersection at or after the
ray origin. A ray that starts inside a box hits it at distance 0; a box
entirely behind the near plane is not hit at all. out is truncated to the
number of hits, so an empty array means nothing was picked.
Skipped rather than reported, in both cases because no meaningful answer
exists: a candidate with an empty or inverted box (the min = +Infinity
convention of an empty geometry), and one whose world matrix is singular
(a zero scale somewhere up its chain), which cannot be inverted and describes
a node collapsed to nothing. A degenerate camera whose ray has no direction
yields no hits at all.
node.hitTestMode selects each candidate's strategy — the module header
has the full table. In brief: null (the default) refines the box hit by
whatever the candidate carries; "bounds", "geometry" and "pixel"
force one strategy, the latter two throwingFourError
(INVALID_APPLICATION_STATE, §85) when their box is hit but the candidate
carries no Pickable.triangles / Pickable.alphaMask; and a
"gpu" candidate is never tested here at all. A geometry-refined hit
reports the distance and point of the triangle actually under the pointer,
not the box entry.
Allocation follows plan D7: pass out and the steady state allocates
nothing — the hits are pooled per array and rewritten in place, which is why
a hit (and its point) read after the next pick into the same array
describes a different intersection. Omitting out allocates a fresh array
for authoring convenience.
depthRange is forwarded to createPickRay; see there.
Tests the picking ray through
(ndcX, ndcY)against every candidate and returns the hits, nearest first (§71).Each candidate is tested in its own local space — the ray is transformed by the inverse of the node's world matrix, so a rotated or non-uniformly scaled box is tested exactly rather than as an inflated world-space AABB (see the module header). World matrices are resolved on demand per candidate, so the result is correct mid-frame without a preceding resolve pass.
Every hit reports the entry point: the first intersection at or after the ray origin. A ray that starts inside a box hits it at distance 0; a box entirely behind the near plane is not hit at all.
outis truncated to the number of hits, so an empty array means nothing was picked.Skipped rather than reported, in both cases because no meaningful answer exists: a candidate with an empty or inverted box (the
min = +Infinityconvention of an empty geometry), and one whose world matrix is singular (a zero scale somewhere up its chain), which cannot be inverted and describes a node collapsed to nothing. A degenerate camera whose ray has no direction yields no hits at all.node.hitTestModeselects each candidate's strategy — the module header has the full table. In brief:null(the default) refines the box hit by whatever the candidate carries;"bounds","geometry"and"pixel"force one strategy, the latter two throwingFourError(INVALID_APPLICATION_STATE, §85) when their box is hit but the candidate carries no Pickable.triangles / Pickable.alphaMask; and a"gpu"candidate is never tested here at all. A geometry-refined hit reports the distance and point of the triangle actually under the pointer, not the box entry.Allocation follows plan D7: pass
outand the steady state allocates nothing — the hits are pooled per array and rewritten in place, which is why a hit (and itspoint) read after the nextpickinto the same array describes a different intersection. Omittingoutallocates a fresh array for authoring convenience.depthRangeis forwarded to createPickRay; see there.