Level-set from a triangle mesh

Hi,

I am looking for advices and suggestions regarding the level-set meshing capabilities of mmg3d. More specifically, I was wondering if it was possible to get a nice tet-mesh from mmg3d, given an input triangle mesh (possibly dirty). I am ok with the result being non-conforming, up to a certain tolerance. I have tried to sample the SDF to the original triangle mesh in various ways (regular grid, adaptive mesh, etc.), but no matter how I try, the output of the level-set mesher produced by mmg is always super ugly (jagged surface). Even for a smooth input such as the Standford bunny the results are disappointing.

Thus I am wondering if I’m missing anything in particular in the functionalities offered by mmg? I tried playing a bit with the ref indices but it didn’t help. Let me know if you have any suggestion. I know that mmg is not tetgen, but when I look at the example for the implicit meshing on the website I would have expected a less jagged output (maybe I need to smooth/regularize the SDF of my bunny?).

Btw, the more I think about it, the more it looks like mmg3d’s level-set meshing is “just” implementing a marching tet over the background tet mesh. Am I wrong? (Haven’t looked into the code, just guessing). Is there a way to refine/optimize quality based on the sampled level-set, or do we need to defer to mmg3d?

Hi Jeremie,

Yes, the level-set discretization in Mmg is very close to marching tet (we use predfined patterns to split the tetrahedron intersected by the level-set).

Normally, Mmg3d improve the quality of the mesh after the split over the level-set.
Maybe your bad mesh issue comes from spurious sharp angle detection (do you use the -nr option of Mmg to disable this option?) or from a too coarse starting mesh?

For example, I have tried the Stanford bunny testcase :

  1. starting from the bun_zipper.ply mesh of the reconstitution folder, I have filled the holes using the meshlab software (because I don’t have tools to compute the signed distance function from an open surface) to get the bun_zipper_filled.mesh (4.0 MB) surface mesh.

  2. then I have computed the signed distance function of this surface mesh on the cube0.mesh using the mshdist software:

    mshdist cube0.mesh bun_zipper_filled.mesh

  3. Finally, I have discretized the level-set with mmg3d using the -nr option (to not detect sharp angles) and the -hausd 0.005 option (to stay close to the new surface):

    mmg3d_debug cube0.mesh -ls -nr -hausd 0.005

The final mesh has a pretty good minimal quality (0.15). You can see the image of the input surface mesh (left) and of the output one (right) below.

The result is not perfect, for example, there is some staggering effect on the ears of the bunny. To remove it, you can:

  • either start from a thiner mesh,
  • either add a step of mesh adaptation to the level-set before the implicit surface discretization (between the step 2 and 3, you compute a size map associated with your level-set, you adapt your mesh to have a thiner mesh around the level-set area, you compute again the signed distance function of the initial surface on the new mesh).

For more complex test cases, you will need the step of mesh adaptation.

I hope that it will help.

Regards,

Algiane

Hi,

Thanks for the reply, this is helpful. I was using mmg3d through the C API, and this gave me very different result (still get the jagged for a uniform background tet mesh, but the quality of the surface was terrible). I may be setting up something wrong in the API. Does the ref of a tet have an importance? If so, what should it be set to? To retrieve the tet-mesh of the bunny, I keep only the tets with the same ref.
Also, why is it refining like crazy around certain areas? To enforce the Hausdorff bound? But then the ears are jagged, so this is suspicious to me.

Do you think mmg could also reconstruct sharp edges if the -nr option is omitted? I mean this is not Duall Contouring so this seems unlikely.

Hi,

Maybe we have a bug in the API? I will try to run the same test using the library.

Normally the tetra references doesn’t matter (in level-set, we delete it when reading the mesh) but you can try to set it to 0.

You are right, you can keep only the tetra of references 3 (inside mesh).

The refinement in some areas is due to the Hausdorff parameter: Mmg detects high curvatures so it insert points to have a discretization sufficiently close from the ideal surface. For the jagged ears, it is because Mmg miss some part of the ears because the initial mesh on which we compute the signed distance function is too coarse to capture the 0 level-set here (for example, the surface is like a gaussian and intersect only 1 face of a tetra, so the signed distance computed is positive at each tetra nodes and Mmg can’t detect that the surface pass through this tetra).

Yes, if you omit the -nr option, Mmg will try to detect sharp angles : first, it will split your mesh on the level-set, then, it will analyze the new surface and mark as sharp angle the edges at the interface of two triangles that creates an angle smaller than 3 Pi / 4.

Regards,

Algiane

I think I just forgot to turn on the mesh optimization params in the API. I’m testing a bit more to see what I can get. Do you have any suggestion on how to define the sizing field in order to adapt to the SDF? E.g. with respect to the min/max edge length and the desired Hausdorff distance.

PS: Oh and is there a reason to use reference 3 for the inside? Why not 0/1?

Your parameters will depend on the bounding box of the including cube mesh and of the size of the surface mesh in this cube.

The mshdist software resize automatically the embedded surface such as its bounding box is 0.75 times the cube bounding box. In this case, and for the [0;1]x[0;1]x[0;1] including cube, I would use a hausdorff of 0.002 or 0.001, with a relaxed gradation (1.6 or 1.8). Optionnally, you can set the hmin parameter to 0.0005 to avoid very small edges.

Of course, it is a first guess for the parameters, it mostly depends on your surface (and the details in it) and on the software that will use your output mesh (does it needs a high quality mesh? if not, you can use an higher value for the gradation…).

There is no real reason for the 2 and 3 references (outside, inside) except that very often, the 0 reference means “no reference” at all.