ManifoldPlus icon indicating copy to clipboard operation
ManifoldPlus copied to clipboard

Simplify complex meshes

Open atenpas opened this issue 3 years ago • 8 comments

Is there a way to simplify the mesh (i.e., reduce the number of vertices and edges) that works with complex mesh shapes? With the mesh, I mean the mesh that's produced by manifold.

I've tried to use simplify from your Manifold project. This works for simple shapes, like a box. However, for certain complex shapes, such as a bowl, it results in this error:

simplify: /home/andreas/software/Manifold/3rd/igl/per_vertex_point_to_plane_quadrics.cpp:95: igl::per_vertex_point_to_plane_quadrics(const MatrixXd&, const MatrixXi&, const MatrixXi&, const MatrixXi&, const MatrixXi&, std::vector<std::tuple<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1>, double> >&)::<lambda(const RowVectorXd&, const MatrixXd&, double)>: Assertion `std::abs(S.row(j).dot(ei)) < 1e-10' failed. Aborted

This is the mesh: bowl.tar.gz.

atenpas avatar Jul 31 '20 16:07 atenpas

I also had this issue. My solution was to use the mesh simplification script that comes with MeshLab. The function "Simplification: quadratic edge collapse decimation" with a desired percentage reduction of for example 0.1, preserving boundary of the mesh etc. This action can then be automated to run from the command line similarly to the original simplify script from the other repo. Let me know if you need further help

CallumMcMahon avatar Aug 04 '20 15:08 CallumMcMahon

@CallumMcMahon Thank you for the suggestion! I am in a similar situation; could you please point me to MeshLab's mesh simplification script and give a few hints about automating it to run from the command line. Thanks!

unlugi avatar Oct 19 '20 13:10 unlugi

@unlugi No problem! With MeshLab installed, load up a mesh, then select filters -> Remeshing, Simplification and reconstruction then chose one of the simplification methods. tweak the settings until you get satisfactory results. You might want to try these settings on multiple meshes from your dataset to make sure they generalise well. Specifying a percentage reduction instead of a target number of faces may genealise better for example. Note that some methods break the manifold-ness ("repair non manifold vertices by splitting" may help).

Once a proper workflow is established, select filters -> show current filter script -> save script

This script can be run by calling the meshlab server from the command line, passing the script and mesh to process as arguments. This allows you to chain the manifoldPlus script followed by the simplification script in a Bash file looping over each mesh to process. I learned bash for this project so the following code is very messy and will need quite a lot of playing around with but should be an alright starting point. Note that the way you call meshlab server can change based on how it was installed. I've seen people just call meshlabserver but my snap install needed snap run meshlab.meshlabserver

#!/bin/bash
# produces a folder for manifoldPlus output and another for the further simplified data
outputFolder="manifoldSimp"
simplificationScript="simplification.mlx"

for category in data/style/*; do
  if [ -d $category ]; then
    [ -d $category/manifold ] || mkdir $category/manifold
    [ -d $category/$outputFolder ] || mkdir $category/$outputFolder
    for filename in $category/train/*.obj; do
      echo $(basename "$filename") "$filename"
      [ -f "$category/manifold/$(basename "$filename")" ] || ./ManifoldPlus/build/manifold --input "$filename" --output "$category/manifold/$(basename "$filename")" --depth 8
      [ -f "$category/$outputFolder/$(basename "$filename")" ] || snap run meshlab.meshlabserver -i "$category/manifold/$(basename "$filename")" -o "$category/$outputFolder/$(basename "$filename")" -s "$simplificationScript"
    done
  fi
done

My chosen model (meshCNN) produced OOM errors for meshes that were still too large after simplification (a problem of using percentage reduction simplification). You can call compute topological measures within meshlab and parse the output to console to automatically remove large meshes during processing. This isnt recommended for doing like-for-like comparisons with other methods but can trim down the dataset for quick prototyping.

#!/bin/bash
# Skips meshes that start with over 90000 faces, and also doesn't output a file if the processed mesh does not end up less than 20000 faces
# name of class subfolder where remeshed files will be saved
outputFolder="trimmed"
meshInfoScript='getMeshInfo.mlx'
# link to meshLab script
simplificationScript="simplification.mlx"
# regex to extract number of faces from script output
regex='([0-9]+) fn'

function runMeshLabScript {
  # input location:   $1
  # output location:  $2
  # script to use:    $3
  # return:           array {input#faces, output#faces}
  mapfile -t output < <(snap run meshlab.meshlabserver -i "$1" -o "$2" -s "$3" 2>/dev/null |
          while IFS= read -r line; do
            if [[ $line =~ $regex ]]; then
              name="${BASH_REMATCH[1]}"
              echo $name
            fi
          done)
}

for category in data/style/*; do
  if [ -d $category ]; then
    # make sub-folder if it doesn't not already exist
    [ -d $category/$outputFolder ] || mkdir $category/$outputFolder
    for filename in $category/train/*.obj; do
      echo $(basename "$filename") "$filename"
      # check if file has already been processed
      if [ ! -f "$category/$outputFolder/$(basename "$filename")" ]; then
        # if mesh has too many faces to begin with, give up
        runMeshLabScript $filename $category/$outputFolder/$(basename "$filename") $meshInfoScript
        echo "mesh has ${output[0]} faces"

        if ((output[1] > 90000)); then
          echo "to be deleted"
          rm "$category/$outputFolder/$(basename "$filename")"
        else
          # parse output of script for input and processed mesh number of faces
          runMeshLabScript "$filename" "$category/$outputFolder/$(basename "$filename")" "$simplificationScript"
          echo "remeshed and simplified to ${output[1]} faces"
          # throw away mesh if it is above a certain number of faces. Too computationally expensive to process by model
          if ((output[1] > 20000)); then
            echo "to be deleted"
            rm "$category/$outputFolder/$(basename "$filename")"
          fi
        fi
      fi
    done
  fi
done

I've since moved on from this project but let me know if you need any other help

CallumMcMahon avatar Oct 19 '20 16:10 CallumMcMahon

@CallumMcMahon Thank you so much for the detailed explanation and suggestions. I am trying it out for myself right now.

unlugi avatar Oct 20 '20 08:10 unlugi

@CallumMcMahon @hjwdzh Hi, I also met such a problem and I have also tried meshlab to simplify the mesh from ManifoldPLUS. Some of the output from ManifoldPLUS have some holes in the surface, like this one: 6e39ef8ceb12eed8825dad1fbbe81ce.

Some other ManifoldPLUS outputs do not have such holes. But if I apply "Simplification: quadratic edge collapse decimation" from meshlab on it, some holes appear, like this one: 1652434573(1)

Do you have any suggestions on how to fix it? Whether on meshlab or some other method is ok. Looking forward to you reply. Thank you very much!!

1999kevin avatar May 13 '22 09:05 1999kevin

@1999kevin Hi, have you solved the problem? I'm also trying to use Meshlab to simplify the meshes and find that it produces non-watertight meshes with holes. Do you have some advice?

bluestyle97 avatar Jun 27 '22 08:06 bluestyle97