Martin
Martin

Reputation: 171

Most Efficient Way to Calculate an SDF to a Triangle Mesh

SDF from triangles, edges and vertices

Hi.

I've been gathering info from various sources consistently over the past month, yet without any luck of finding an idea that would suit my particular issue. So here's the formulation of the problem:

Given a mesh in a form of buffer geometry (32-bit arrays of vertex coords and vertex indices + additional arrays, such as vertex normals, uvs, or tangents) calculate a signed distance function (SDF) for a uniform grid of points surrounding the geometry.

To be more specific, I intend to create something resembling a MetaBall object in 3D engines such as Maxon's Cinema4D or Blender. I've successfully implemented distance functions for all geometric primitives, but an arbitrary mesh SDF required me to implement a brute force approach - testing the distance for each triangle of the mesh for each grid point - which, of course, gets really slow for complex meshes.

Now, I recalled that most of these problems require one to build a tree-like structure, such as an Octree, KD-tree, BSP-tree, or an AABB-tree. Then I found a few articles on the so-called Fast-Sweeping algorithm (for solving an Eikonal equation) which requires one first to fill the grid points laying on the boundary (in my case the mesh, or closest to the mesh) with 0 and the remaining with large values (Infinity) and then solve the non-linear hyperbolic boundary value problem iteratively (Gauss-Seidel). I also found an open-source implementation of a mesh SDF method in the CGAL library. Alternatively, I also thought about using some shader library (like GLSL) and perhaps try building the trees using GPU, but I have never used shaders in a JS or TS project.

The step I keep getting stuck on isn't just picking the best option, but actually practically using, at least one of these methods efficiently. For example:

I thought about combining multiple approaches, but it all seems very time consuming. I also thought of using the CGAL library, or perhaps refactoring it for the purposes of my project, but I find it quite difficult to understand the C++ code because of all the dependencies inside the library. Has anyone of you done something similar to this? What would you recommend?

Thank you for all the insights.

Upvotes: 11

Views: 5716

Answers (1)

Martin
Martin

Reputation: 171

I solved this using an approach outlined by three (four) main steps:

  1. Generate an AABB tree of the mesh triangle soup

  2. Use the AABB tree to subdivide regular bounding cubes whenever a cube intersects the mesh (fast intersection using AABB tree) forming an Octree. When subdivision reaches leaves, exact squared distances (cube centroid to triangle) are computed and a square root is taken of the smallest, writing it into a regular grid based on cube min-max coordinates.

  3. Using exact distance values on mesh-intersecting voxels and a large value elsewhere, run the Fast Sweeping algorithm 8 times and fill the scalar grid with distance values.

  4. (optional) flood fill the outside voxels of a negated distance grid to make sure voxels inside an outline of marked initial voxels (with exact values) have negative sign (this is, unfortunately, the slowest part for grids with resolution > 100^3 )

For a more detailed look on my implementation with computation times, feel free to read my blog posts: https://mshgrid.com/blog/

Thanks for the upvotes and comments :) .

Upvotes: 5

Related Questions