A mean curvature viewer based on Polyscope.
A simple C++ viewer for mean curvature vizualization of triangular meshes, built upon the 3D data manipulation and vizualization library Polyscope.
Supports .obj
, .ply
, and .off
files.
The implementation is based on "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds, Meyer et al". Specifically, the mean curvature K(xi) vector at each vertex of the mesh xi is computed according to:
For the computation of the vertex area Amixed two approaches are considered:
- Voronoi vertex areas are computed according to the the algorithm described in Fig.4 of the afforementioned paper.
- Barycentric areas are provided natively by Polyscope.
To download, run:
git clone --recurse-submodules https://github.com/alexdkeros/Curvscope.git
To compile the code, navigate to the project's directory and run:
mkdir build
cd build
cmake ..
make
The executable will be located in <project directory>/build/bin/curvscope
.
In order to launch the viewer, from the project's directory, run:
./build/bin/curvscope [path/to/mesh1.obj path/to/mesh2.ply path/to/mesh3.off ...]
(Command line arguments are optional)
How to use the Command UI:
Curvscope only depends on Polyscope, which packages all its source code dependencies with the repository.
Polyscope is included as a git submodule
.
In the following examples mean curvature is computed with Mean Curvature (Voronoi areas)
:
Mean Curvature (Voronoi areas) | Mean Curvature (Barycentric areas) |
---|---|
![]() |
![]() |
Barycentric areas can cause irregularities in curvature computation due to triangulation peculiarities, as seen below:
Voronoi vertex areas | Barycentric vertex areas |
---|---|
![]() |
![]() |
Similarly to the torus case, barycentric vertex areas on the sphere can cause outliers in curvature computation.
Mean Curvature (Voronoi areas) | Mean Curvature (Barycentric areas) |
---|---|
![]() |
![]() |
A very crude implementation of mean curvature flow, according to the computed mean curvature vectors. Unfortunately, when face areas become too small singularities cause them to get deleted.
Before | After |
---|---|
![]() |
![]() |
![]() |
![]() |
An alternative approach would be to use libIGL, a handy geometry processing library. To this end, one only needs to clone the Polyscope-libIGL project template and add the following functions in main.cpp
, with their respective callbacks. Examples of these functions are provided in the libIGL tutorial.
The Laplace-Beltrami operator approach:
void addMeanCurvatureScalar() {
using namespace Eigen;
using namespace std;
MatrixXd HN;
VectorXd H;
SparseMatrix<double> L,M,Minv;
igl::cotmatrix(meshV,meshF,L);
igl::massmatrix(meshV,meshF,igl::MASSMATRIX_TYPE_VORONOI,M);
igl::invert_diag(M,Minv);
HN = -Minv*(L*meshV);
H = HN.rowwise().norm(); //up to sign
polyscope::getSurfaceMesh("input mesh")
->addVertexScalarQuantity("mean curvature", H,
polyscope::DataType::SYMMETRIC);
polyscope::getSurfaceMesh("input mesh")
->addVertexVectorQuantity("mean curvature vectors", HN);
}
The Quadratic fit approach:
void addMeanCurvatureQuadFitScalar() {
using namespace Eigen;
using namespace std;
VectorXd H;
MatrixXd PD1,PD2;
VectorXd PV1,PV2;
igl::principal_curvature(meshV,meshF,PD1,PD2,PV1,PV2);
// mean curvature
H = 0.5*(PV1+PV2);
polyscope::getSurfaceMesh("input mesh")
->addVertexScalarQuantity("mean curvature (QuadFit)", H,
polyscope::DataType::SYMMETRIC);
polyscope::getSurfaceMesh("input mesh")
->addVertexVectorQuantity("Principal vec1", PD1);
polyscope::getSurfaceMesh("input mesh")
->addVertexVectorQuantity("Principal vec2", PD2);
}
Timing comparisons on example meshes (average of 10 executions):
Mesh | Ours (Voronoi vertex areas) | Laplace-Beltrami operator | Quadratic fit |
---|---|---|---|
spot | 3ms | 118ms | 2764ms |
bunnyhead | 1ms | 67ms | 1528ms |
Example mean curvature vizualization on bunnyhead
(colorscale range [0-20]):
Ours (Voronoi vertex areas) | Laplace-Beltrami operator | Quadratic fit |
---|---|---|
![]() |
![]() |
![]() |