mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.7k stars 35.37k forks source link

Request: Allow raycast function to prevent traversal of children #18853

Closed gkjohnson closed 3 years ago

gkjohnson commented 4 years ago

Request

Allow raycast function to prevent traversal of children so the parent object can handle custom raycasting for the child objects.

Use Case

I'm currently writing a 3D Tiles renderer library for three.js and I would like to take advantage of the bounding volume hierarchy for raycasting. For context the 3D Tiles format specifies a hierarchy of geometry that is swapped out as the camera gets closer. Each level of the tree has a bounding box that encapsulates all the child tiles. The bounding hierarchy should be able to be used to improve raycast performance by culling parts of the potentially deep tree more quickly. In the library all visible tiles viewable by the camera are added as children of a parent group called TilingGroup.

I would like to perform the hierarchy check in TilingGroup.raycast and only call intersectObjects on the geometry within the appropriate bounds. However the way Raycaster works right now all children are always traversed, which means there's no opportunity to check the the bounding tree before performing raycasts.

One approach would be to allow raycast to return a boolean which would prevent the Raycaster from traversing the Groups children, but that might not play nice with the new Layers functionality. Another option would be to move some of the raycast traversal logic into Object3D.raycast so it can be overridden.

Maybe there are some other suggestions? I've looked a few different options but so far I've come up empty.

Thanks!

Mugen87 commented 4 years ago

I think you should be able to control if objects should be affected by raycasting via Raycaster.layers which was added in R114.

gkjohnson commented 4 years ago

That's true but it doesn't seem like the right way to handle it. The 3D Tiles loader is intended to be a library for other applications to use and I'd like it to "just work" when being dropped in the way we expect loaders in examples to just work. The containing application shouldn't have to know anything about how tiles are being added and removed from the scene and how raycasting is working.

If I could I would keep the tiles in another scene and render them in something like an onBeforeRender function but there's nothing that makes that possible at the moment and there's no way to retain lighting across the scenes.

makc commented 4 years ago

@gkjohnson just

yourObject.children.forEach(function (child) { child.raycast = function () {} });

(or traverse, if children are nested)

gkjohnson commented 4 years ago

@makc

Thanks I was thinking about doing that, as well. I hoping to not override the object functions on an result returned from a loader but it will work!

Mugen87 commented 3 years ago

Sorry, but I don't think it's appropriate to add a more advanced API for this use case. Layers are already a quite generic approach and there are workarounds like the one of @makc if you need more flexibility.

In all other cases, it's better if you implement a custom solution on top of three.js.