Optimize geometry with interpenetration

I have complex, procedurally (at runtime) generated geometries that get merged down to one single BufferGeometry using BufferGeometryUtils.mergeGeometries .

The resulting geometry has lots of interpenetration that I would like to reduce, i. e. there are triangles that will never be visible because they are completely enclosed by opaque volumes of geometry. I would like to remove those triangles from the geometry.

Is there a free library that would help with this task? Can you recommend an efficient approach?

The solution of my dreams would be an algorithm/library that can actually reduce the geometries to a single continuous surface, ideally with variable smoothness at the seams.

There’s no one-shot method I’m aware of that will cleanly reduce arbitrary triangle soups into a single watertight surface, but there are a few tools and concepts that can help depending on how structured your geometry is.

If your meshes already form proper closed volumes, CSG libraries (like three-bvh-csg) can help eliminate internal faces. These typically rely on BSP trees or acceleration structures to classify and clip geometry.

But if you’re working with non-volumetric triangle soup — single planes, intersecting slabs, disconnected pieces — then defining an “interior” becomes ambiguous. A triangle by itself doesn’t enclose anything, whereas a tetrahedron is the minimal volumetric primitive.

Convex hulls are another tool that can approximate outer boundaries, but only work well for convex-ish shapes and don’t preserve details. (threejs: ConvexGeometry)

For topological reasoning, half-edge data structures (DCELs) can be helpful for navigating edges and face adjacency. (Look for halfEdge in threejs docs/repo)

As for your idea of “variable smoothness at seams,” that sounds like an edge split modifier, common in tools like Blender, which lets you preserve hard edges while smoothing others. (There is also a version of this modifier available in threejs)

In short, there’s no silver bullet for this, but combining volumetric structure, CSG, convex hulls, and maybe voxelization + surface extraction (marching cubes) can get you closer, especially if you’re willing to preprocess offline.

2 Likes

Thanks, manthrax.

Fortunately, the meshes are not random polygon soup, they’re always closed volumes that are basically always interpenetrating to some degree. It’s three to eight convex and concave “watertight” meshes that get combined to one complex object.

The resulting objects are “only” 1,500-2,500 triangles, and maybe up to 25% of that enclosed by solid geometry in the worst case. There’s never more than ~50 objects on the screen. I’m not quite sure whether a lot of R&D effort is justified or if I can just ignore the waste and forget about smooth merge. I’ll probably be fillrate-limited anyway before poly count becomes an issue.

Oh in that case.. mesh-bvh-csg is the way to go! It can perform “union” of multiple watertight meshes (concave or convex) a will give you just the surface.

And yes.. its most likely a premature optimization. I would only worry about it if the interpenetration causes artifacts you don’t want.

Just for personal entertainment tried one stupid geometry optimization. The red object eats whole faces from the gray object. Triangles are not split as in CSG.

https://codepen.io/boytchev/full/PwqYmQW

image

2 Likes

That’s pretty cool, Pavel. Using ray casting was my first idea as well, but dismissed it because of performance considerations.

I’m looking into mesh-bvh-csg, I think it will probably work out for my use case. Thanks, all.

1 Like