Stopping a raycast on first object hit?

I’m currently raycasting on mouseMove, an array of objects in the scene and I realistically only need the very first object that is hit, nothing else after that. It seems wasteful to continue the cast & search despite my result already being satisfied. Is there a built-in way of doing this, if not, would it be easy to hack in?
Or would the performance improvement be minuscule?

Thanks!

I assume you are using Raycaster.intersectObjects(), right? The method tests the entire given array of 3D objects and sorts the intersections per distance since in many use cases you want the closest intersection point (and not just an arbitrary one). If you do not need this logic in your app, I suggest you use Raycaster.intersectObject() instead and raycast against each object individually. You can then abort the intersection test as soon as you have an intersection point.

2 Likes

Not sure why I didn’t think of that, seeing as Raycaster.intersectObjects does that internally anyway, I believe, just sorts the end result by distance. Thanks!

1 Like

I didn’t know about the singular intersectObject() until I read this thread. That is awesome :slight_smile:

1 Like

That’s why it’s good to read the documentation… time to time :beers:

1 Like

I am coming from OpenSim, docs are a new concept that I am getting used to. :wink:

1 Like

At first I thought this idea works, but after implementing it, figured out that if two objects are behind each other, and if you don’t search in all 3D objects for intersection, you may check the object behind the closer object first. So I think this approach only works when you don’t have objects behind each other.

@ahmafi

At first I thought this idea works, but after implementing it, figured out that if two objects are behind each other, and if you don’t search in all 3D objects for intersection, you may check the object behind the closer object first. So I think this approach only works when you don’t have objects behind each other.

It’s a bit more complicated than just taking the first intersection you find. You’ll want to take your array of objects, sort by the objects bounding box intersect distance down the ray, check every object in ascending order, and then stop when the closest bounding box point is further than closest discovered triangle intersection.

To be honest this might be a nice be a nice optimization to include in three.js itself. I would think it would be fairly common that people are only looking for the first intersection in a scene rather than all of them. The raycast function could take a distance threshold to tell it when the intersection is no longer relevant help afford this: mesh.raycast( raycaster, intersects, maxDistance ) (thoughts @Mugen87?).

A bit of a self-plug but the three.js mesh BVH plugin I maintain enables this per-geometry so a minimal amount of triangles are checked and only the closest intersection is returned for that geometry when raycast.firstHitOnly = true, which provides a pretty significant performance improvement with large complex geometry:

That won’t help in scenes with lots of simple objects, though.

3 Likes

Thanks for your replay. I just used your BVH implementation in my project and it really helped me out, great job. And yes, it’s more complicated, I saw the implementation in three.js and it’s kinda a simple algorithm, there is a lot of space for optimization.

1 Like

Thanks this helped me out a lot on my robot battle game. I kept firing through the landscape and boulders. Now the raycaster stops at the first object detected. Now I have to add laser burns when I hit the boulder… :smile: :smile: