three-mesh-bvh icon indicating copy to clipboard operation
three-mesh-bvh copied to clipboard

raycastFirst does not stop on first hit

Open obrhaberer opened this issue 1 year ago • 4 comments

Describe the bug

The performance feature raycastFirst does not stop on first hit and gives intersections.length > 1.

To Reproduce

Init raycaster as documented and set firstHitOnly to true. Raycast will give more than one intersection.

Code

init as documented

THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree THREE.Mesh.prototype.raycast = acceleratedRaycast

const raycaster = new THREE.Raycaster() raycaster.firstHitOnly = true

const intersects = raycaster.intersectObjects(objects)

intersects.length > 1 // true

Expected behavior

acceleratedRaycast with firstHitOnly = true should give length <= 1

Screenshots

If applicable, add screenshots to help explain your problem (drag and drop the image).

Platform:

  • Device: Desktop
  • OS: MacOS
  • Browser: Chrome
  • Three.js version: 144
  • Library version: v0.5.16

obrhaberer avatar Sep 06 '22 08:09 obrhaberer

Perhaps the documentation could be updated but setting raycaster.firstHitOnly only affects the behavior at the individual Mesh level - ie when performing a raycast into a mesh it will early out once the closest hit is found as an optimization. The raycaster.raycast function will still return multiple intersections if multiple meshes are intersected with even if it just returns at most one intersection per mesh. This is as designed.

gkjohnson avatar Sep 07 '22 02:09 gkjohnson

raycaster.firstHitOnly can deliver more than two intersections for raycaster.intersectObjects([mesh1, mesh2]) as a result if the material.side is DoubleSide. Is this also as designed?

obrhaberer avatar Sep 07 '22 06:09 obrhaberer

Could there be a benefit to provide a firstHitOnly which gets the first hit from the first mesh and than sets the far parameter for the next mesh/iteration?

obrhaberer avatar Sep 07 '22 06:09 obrhaberer

raycaster.firstHitOnly can deliver more than two intersections for raycaster.intersectObjects([mesh1, mesh2]) as a result if the material.side is DoubleSide. Is this also as designed?

This doesn't sound right. Can you provide a demonstration of the issue?

Could there be a benefit to provide a firstHitOnly which gets the first hit from the first mesh and than sets the far parameter for the next mesh/iteration?

This would be a better role for a scene-level spatial index. Something like #388 or an octree implementation would be a better general approach for this. In your app you could also collect all the meshes that you anticipate intersecting, sort them by distance along the ray, and then perform per-mesh intersections until you know you've found the closest one so you can early out.

gkjohnson avatar Sep 07 '22 22:09 gkjohnson

Going to close this - it's possible to write a better raycaster that would work for three.js without a BVH by presorting the geometry but I think that's outside the scope of this project for the moment.

gkjohnson avatar Nov 20 '22 01:11 gkjohnson