gkjohnson / three-mesh-bvh

A BVH implementation to speed up raycasting and enable spatial queries against three.js meshes.
https://gkjohnson.github.io/three-mesh-bvh/example/bundle/raycast.html
MIT License
2.55k stars 268 forks source link

ClosestPointToPoint: Signed Distance #704

Open zalo opened 2 months ago

zalo commented 2 months ago

Is your feature request related to a problem? Please describe.

A lot of really interesting mesh algorithms rely on signed distance fields, so having the BVH output signed distance would be great!

Describe the solution you'd like

I'd like ClosestPointToPoint to automatically adjust the sign of the distance depending on whether the point is inside the mesh.
Ideally it handles edge cases, like the one where the reported nearest triangle has a normal pointing away from the sample point: image

Describe alternatives you've considered

My first implementation tried adding up the normals on the adjacent triangles to the closest point to get a super normal, but even area-weighting it was still susceptible to bad edge-cases.

I've began to write a more advanced implementation here: https://github.com/gkjohnson/three-mesh-bvh/compare/master...zalo:three-mesh-bvh:master If the closest point is on an edge or vertex, it attempts to sum up the solid angle/winding number of the adjacent triangles to determine which side the point is on. However, it doesn't seem like even this implementation is totally robust; it seems to be marking spurious external points as internal...

Is there perhaps some built-in aspect of the bvh that can efficiently determine insidedness?

Additional context

You can see sort of see the behavior I'm talking about here in this Hydroelastic Contact testbed; it's a bit hard to see though... HydroelasticContacts3

gkjohnson commented 2 months ago

Unfortunately a generalized BVH alone cannot reliably detect containment for an arbitrary mesh. In order to determine containment a mesh needs to have distinct inside and outside which means that a mesh must be manifold - or every edge must have a sibling edge so it can be considered "solid" and there are no requirements in this library for that. The suzanne model notable does not have these properties if you look at the eye geometry. As it seems you've already seen - the SDF example demonstrates how to determine containment with the results of the closestPointToPoint function, though it's not resilient to the case you've listed. Alternatively you could cast a ray and check back faces or use the ray-crossing algorithm to determine whether a point is contained.

You can likely come up with a variety of different approaches to generating a signed distance field for these kinds of non-solid geometry but I don't think that's something that's within this scope of this library.

zalo commented 2 months ago

Ah I hadn’t actually taken the time to verify whether Suzanne was manifold or not 😅

Would you be open to me adding some topology debug info fields to the BVH construction so users can verify their own meshes?

Happy to forget Suzanne in favor of manifold meshes.

gkjohnson commented 2 months ago

Would you be open to me adding some topology debug info fields to the BVH construction so users can verify their own meshes?

A feature like this is outside the scope of what this library is for and checking manifold-ness will slow things down even for those who don't need it - there's no reason to tie this to BVH construction. Whether a geometry is manifold or not can and should be done before the creation of a BVH.