Raycasting a gltf-model without using recursive option

Hey there,

I’m trying to load gltf-models into my scene and detecting clicks on them. I’d prefer to make this happen without traversing the parents of the intersected object because of possible performance issues. If those are negligible, please let me know! :wink:

I’m currently loading my models and adding them to an Object3D. That Object3D is then used for detection in the raycaster. If I don’t use the recursive option on the raycaster, clicking on it won’t be detected (intersectedObjects returns an empty array). If I do turn on recursive, it will intersect with a grand-grandchild of the Object3D. Since I want to call a function on the Object3D, I’d prefer not to use recursive. Is there something I can do to make this work?

If I need to explain better, please let me know. Thanks in advance for any help offered!

1 Like

For this to work you need bubbling and a real event system. Three does not have that, you can’t raycast groups and containers unless you do it recursively.

I believe there are only two options.

r3f has pointer events, bubbling and all. You can put events on groups and the group itself will get called back on. It only raycasts objects that have handlers. You can try it out: https://codesandbox.io/s/floating-shoe-mz11v

I’ve also seen three.interaction https://github.com/jasonChen1982/three.interaction.js but haven’t tried it. From just the GitHub repos readme it looks good.

Recursive raycasting means the raycaster considers every object in the scene, regardless of its depth. If you skip meshes deeper in the scene, you’ll miss clicks on them. So, I don’t think it’s quite correct to think of this problem in terms of enabling/disabling the recursive option — an equal number of objects, all at depth=1, would have the same performance problem even with recursion turned off.

Instead, you might want to consider precomputing some information about the scene, so that you can avoid raycasting against objects that haven’t moved. For example, you might precompute a bounding box for each parent object with bbox = new Box3().setFromObject(parent), and raycast against that. If the raycast fails, you can skip all of the parent’s descendants. If the raycast hits, you’ll need to do a (recursive) raycast against the parent. Three.js already uses a cache like this for individual objects to avoid unnecessarily iterating over vertices, but not for an object’s children.

I think @drcmda’s suggestions of bubbling and an event system are solid ways of structuring your solution, but underneath that you still need to choose when and how to raycast.

2 Likes

Hey guys, thanks for both your replies!
I think the solutions @drcmda provides won’t perform any better as it sounds like they will do some recursive things in the background too.
I guess bounding all parent as suggested by @donmccurdy would be an effective solution, except for the overhead. Thing is, all my objects already have a wrapping Object3D, but if I understand your replies correctly the raycaster will only intersect with Meshes, not Object3Ds?

In the meantime I implemented a recursive solution and the amount of iterations isn’t nearly as bad as I was afraid it would be.

Right, the Raycaster will never find an intersection with an Object3D or Group instance. These are empty containers without shape or volume, from the Raycaster’s perspective.

If the recursive solution is performing well enough I’d go with that — the automatic bounding box cache on each mesh helps a lot with this. But If you do run into limits there, the overhead of creating bounding boxes for parent objects should really be quite low, as long as you use the bounding boxes of their descendants and not the raw vertex data. There are also more complex ways of dealing with these things like BVH structures, but I wouldn’t go into that unless raycasting really becomes a bottleneck for you.

1 Like