Skip to content

Raycaster does not intersect PointsNodeMaterial instances (WebGPU/TSL) #32568

@webwitcher

Description

@webwitcher

Description

When rendering interactive handles as instanced points using WebGPU + TSL (PointsNodeMaterial with positionNode = instancedBufferAttribute(...)), Raycaster does not return any intersections. Other scene objects (planes, lines, meshes) intersect correctly in the same pass. Adjusting raycaster.params.Points.threshold has no effect for these points.

Environment

  • Renderer: WebGPURenderer
  • Material: PointsNodeMaterial (TSL)
  • three.js: v0.182.0
  • Browser/OS: Chrome v142.0.7444.176/Win11

Snippets

  • Handle creation (instanced positions with PointsNodeMaterial)
// Build one instanced buffer with all handle positions
const positions = new Float32Array(verticesCopy.length * 3);
verticesCopy.forEach((vertex, i) => {
  positions[i * 3] = vertex.x;
  positions[i * 3 + 1] = vertex.y;
  positions[i * 3 + 2] = vertex.z;
});
const positionAttribute = new InstancedBufferAttribute(positions, 3);

// PointsNodeMaterial (TSL), constant on-screen size
const sizeUniform = uniform(this.HANDLE_SIZE_PX);
const material = new PointsNodeMaterial({
  color,
  positionNode: instancedBufferAttribute(positionAttribute),
  // opacityNode: shapeCircle(), // also tested on/off
  sizeNode: sizeUniform,
  sizeAttenuation: false,
  alphaToCoverage: true,
});

// Render all handles as one draw object
const handles = new Sprite(material);
handles.name = 'OBJECT_HANDLES';
handles.count = verticesCopy.length;
handles.renderOrder = 5;
targetObj.add(handles);
  • Raycaster configuration and usage
// Init
this.raycaster = new Raycaster();
this.raycaster.params.Points.threshold = 5; // also updated dynamically

// Pointer move
this.mouse = this.getNormalizedMousePosition(event);
this.raycaster.setFromCamera(this.mouse, view.camera);

// Query — handles are among the first targets
const objectsToIntersect = [
  ...this.getStackControllerObjs(view),
  ...(this.getActiveOverlayObj(view)?.getObjectsByProperty('name', 'OBJECT_HANDLES') || []),
  // ... other objects (ROIs, landmarks, planes, volumes, bbox, etc.)
];

const hits = this.raycaster.intersectObjects(objectsToIntersect, false);

// Dynamic scaling (no effect on the missing hits)
private updateRaycasterPointThreshold(scaleFactor: number, pointSize: number): void {
  this.raycaster.params.Points.threshold = pointSize * scaleFactor;
}

Expected

  • intersectObjects returns intersections for each visible point/handle rendered via PointsNodeMaterial. Changing raycaster.params.Points.threshold affects hit testing.

Actual

  • No intersections are returned for the handles rendered with PointsNodeMaterial (TSL) using positionNode: instancedBufferAttribute(...). Intersections for other objects work. Toggling transparent, depthTest, alphaToCoverage, and culling does not change this.

Questions

  • Is raycasting supported for PointsNodeMaterial (TSL) with an instanced position node under WebGPU?
  • If supported, is a specific object type required (e.g., must be Points instead of Sprite) for raycasting to work with PointsNodeMaterial?
  • If not supported, what’s the recommended approach for per-point picking with TSL materials under WebGPU?

Screenshots

Image

Version

0.182.0

Device

Desktop

Browser

Chrome

OS

Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions