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.4k stars 248 forks source link

Lasso selection how can I select only surface meshes #389

Closed SivHMA closed 2 years ago

SivHMA commented 2 years ago

Like this image Not opposite grid image

gkjohnson commented 2 years ago

You can read through #109 and #166 for more detailed discussion on the lasso demo but the short answer is that you can't select just the visible faces using just a BVH. You need to using something like a render pass with triangle ids to select just the visible faces.

geoff-harper commented 1 year ago

As something of a 3D noob myself, could something like this be detailed, either in extending the example (probably much work?) or leaving some breadcrumbs here for people to follow?

My understanding is that you mean take the result of the lasso and intersect against each face one by one to see which are obstructed? On the mesh I'm testing with I'm getting ~5k indices with a pretty modest selection. At a high level, are there any optimizations I can make to improve crunching 5k casts at once

gkjohnson commented 1 year ago

You can read up more in #109 and #166 - short of it is that even Blender uses an imperfect solution for determining visible faces by doing something like rendering to a buffer and reading it back to the CPU which can result in missing faces that would be expected to be part of the selection. Determining occlusion is a difficult problem.

Overall I think a detailed discussion on this is out of scope for this project, though. I recommend StackOverflow or the three.js forums or Discord if you want to learn more where the topic will be more visible.

geoff-harper commented 1 year ago

Fair enough. I spent the last 22 hours (wow it took me 22 hours) and I arrived at something workable. For anyone else looking to do this, my impl looks something like

// get the center of the triangle
const centroid = tri.a
  .add(tri.b)
  .add(tri.c)
  .multiplyScalar(1 / 3);

// check for obstruction, dir is Vector3
dir.subVectors(centroid, camera.position).normalize();
raycaster.set(camera.position, dir);
const hits = raycaster.intersectObject(mesh);

// index from intersectTriangles args
if (hits[0]?.faceIndex !== index) {
  return false;
}

// the example continues..
if (contained) {
  indices.push(a, b, c);
  return false;
}

This snippet assumes you're going off of the selection example with the centroid mode I found that casting against the face centroid was the most convenient and accurate. No doubt there are better ways but this seems like a good starting point. Thanks for the quick feedback and the excellent lib 💪 @gkjohnson

gkjohnson commented 1 year ago

Yeah that should work for the centroid case or vertex selection. But as you mention unfortunately that won't work if you're trying to select any triangle that intersects the lasso selection. Glad you found something that works for you!

gkjohnson commented 1 year ago

@geoff-harper I've added your suggestion to the demo in #466. I hadn't considered just supporting selection-occlusion in just the centroid case. Thanks!