Skip to content

fix: volume select ignores splats outside the camera frustum#904

Open
mvanhorn wants to merge 1 commit into
playcanvas:mainfrom
mvanhorn:fix/volume-select-frustum
Open

fix: volume select ignores splats outside the camera frustum#904
mvanhorn wants to merge 1 commit into
playcanvas:mainfrom
mvanhorn:fix/volume-select-frustum

Conversation

@mvanhorn

Copy link
Copy Markdown

Summary

Restructure src/shaders/intersection-shader.ts so the NDC frustum-cull check only gates the screen-space selection modes. Sphere (mode 2) and box (mode 3) now evaluate their world-space predicate unconditionally, so splats inside a volume are selected even when the camera is pointed away from them.

Why this matters

Issue #843 reports that Sphere and Box volume selection only catches splats whose projection sits inside the current camera view - rotate the camera away from the volume and clicking Add selects nothing. Maintainer @slimbuck confirmed on 2026-03-18: "omg you're right. i can't believe it." The bug is the unconditional if (!any(greaterThan(abs(ndc), vec3(1.0)))) frustum cull that wraps every mode-specific predicate. That gate is correct for rect / mask / pixel-precise selection (modes 0 and 1) which operate in screen space, but it is wrong for sphere and box which test world-space containment.

Implementation notes

  • World position is still hoisted before the mode switch so all four modes can read it.
  • NDC computation plus the !any(greaterThan(abs(ndc), vec3(1.0))) cull moved inside an (mode == 0 || mode == 1) branch.
  • Sphere (mode 2) and box (mode 3) branches now run their world-space tests without the NDC gate.
  • Shader uniforms, output channel layout, and the CPU dispatch path in src/data-processor/intersect.ts and src/editor.ts are unchanged.

Testing

  • npm run lint clean.
  • npx tsc --noEmit clean.
  • Walked the diff against the scenarios from the issue:
    • Sphere / box volume placed behind the camera: world-space predicate runs without the NDC gate, splats inside the volume select.
    • Rect / lasso / brush (modes 0 and 1): NDC gate still in place, off-screen splats are still rejected.
    • select.byMask (mode 0): mask sampling still requires valid NDC; behavior unchanged.

Fixes #843

Sphere and Box volume selection only caught splats whose projection sat
inside the current camera view: point the camera away from the volume
and clicking Add selected nothing; aim partially and only the visible
portion was selected.

The root cause was in intersection-shader.ts: the frustum-cull check
"if (!any(greaterThan(abs(ndc), vec3(1.0))))" wrapped every mode's
predicate, gating world-space tests (sphere mode 2, box mode 3) on the
splat also being inside NDC clip space. That gate is correct for
screen-space modes (mask 0, rect 1) which need valid NDC for mask
sampling and rect bounds, but wrong for world-space volume tests which
should be independent of the current view.

The fix restructures the shader body so the NDC computation and frustum
gate only run for modes 0 and 1, while modes 2 and 3 evaluate their
world-space predicate unconditionally. World position is still hoisted
since both volume modes need it. The shader output channel layout,
uniforms, and CPU-side dispatch path remain unchanged.

Refs playcanvas#843

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes volume selection (sphere/box modes) so splats are selected based on world-space containment regardless of camera orientation, by removing the NDC frustum cull from those modes while keeping it for screen-space modes (rect/mask).

Changes:

  • Hoist world-space position computation before the mode switch.
  • Gate the NDC computation and frustum cull behind mode == 0 || mode == 1.
  • Run sphere (mode 2) and box (mode 3) predicates unconditionally in world space.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue: Volume select should ignore camera view

4 participants