Mesh Processing Library
This package contains a C++ library and several application programs that demonstrate mesh processing technologies published in research papers at ACM SIGGRAPH in 1992–1998:
- surface reconstruction (from unorganized, unoriented points)
- mesh optimization
- subdivision surface fitting
- mesh simplification
- progressive meshes (level-of-detail representation)
- geomorphs (smooth transitions across LOD meshes)
- view-dependent mesh refinement
- smooth terrain LOD
- progressive simplicial complexes
The source code follows modern C++11 style and is designed for cross-platform use.
Version 1.0 — 2016-04-28.
Requirements / dependencies
The source code can be compiled with Microsoft Visual Studio 2015 from the included solution (
.sln) and project (
.vcxproj) files, using either the Integrated Development Environment (IDE) or the
The code can also be compiled using
clang compilers (as well as the Microsoft Visual Studio
cl compiler) using a set of
Makefiles designed for GNU
make (available in Unix and in the Windows Cygwin environment).
On Microsoft Windows, the library reads/writes images and videos using Windows Imaging Component (WIC) and Windows Media Foundation (WMF), respectively. Image I/O can also use the standard
libjpeg libraries. Alternatively, if the command
ffmpeg is present in the
PATH, that command is spawned in a piped subprocess to read/write both images and videos.
Compiling using the Microsoft Visual Studio IDE
distrib.sln file and build the solution (typically using the “
ReleaseMD - x64” build configuration).
Executables are placed in the
bin/Win32/debug directory, depending on the build configuration (64-bit versus 32-bit, and release versus debug).
Set the appropriate environment variables and run
(Some alternatives are to set
MD stands for multithreaded DLL.)
Executables are placed in the same target directory as in the IDE.
Compiling using GNU
CONFIG environment variable determines
which of the
Makefile_defs_* configuration definitions are loaded.
For example, to build using the Microsoft
cl compiler (Debug, with 8 parallel processes, placing
*.exe into directory
make CONFIG=win -j8
To build just the library using the
mingw gcc compiler:
make CONFIG=mingw -j libHh
To build the library using the
clang compiler and run the unit tests:
make CONFIG=clang -j test
To build the
Filtermesh program on a Unix environment (into the directory
make CONFIG=unix -j Filtermesh
To build all program and run all demos using the Cygwin
make CONFIG=cygwin -j demos
To run unit tests under all configurations:
make CONFIG=all -j test
(Note that additional options such as debug/release, 32-bit/64-bit, and
compiler tool paths/parameters are set in the various
These need to be adjusted depending on the versions and installation paths of the tools.
For instance, the line “
rel ?= 0” in
Makefile_defs_win specifies a debug (non-release) build, and “
PATH := ” sets the compiler directory.)
Publications and associated programs/demos
After the code is compiled, the demos can be run as follows.
In Windows, create and view all the results using the
In Unix or Windows Cygwin, either run the
or alternatively (and faster), invoke
make to create all results in parallel and then view them sequentially:
All programs recognize the argument
-?) to show their many options.
Filterframe are all designed to:
- read media from
std::cin(or from files or procedures specified as initial arguments),
- perform operations specified by arguments, and
- write media to
For example, the command
- reads the specified image,
- rotates it 20 degrees counterclockwise (with the default reflection boundary rule),
- crops its left and right sides by 100 pixels,
- scales it uniformly to a horizontal resolution of 100 pixels using a 6×6 Lanczos filter,
- adds a 20-pixel blue border on all sides,
- creates an undefined (
alpha=0) rectangular region in the image center,
- fills this region using gradient-domain smoothing,
- outputs some statistics on pixel colors (to
- writes the result to a file under a different encoding.
As another example, the command
Filtermesh -info -signeddistcontour 60 -genus |
G3dOGL -key DmDe
- reads a progressive mesh stream to construct a mesh with 1000 faces,
- reports statistics on the mesh geometry,
- remeshes the surface as the zero isocontour of its signed-distance function on a 603 grid,
- reports the new mesh genus, and
- shows the result in an interactive viewer using the specified view parameters,
- simulating keypresses Dm to enable flat shading and De to make mesh edges visible.
Filtermesh -angle 37 -mark -silsubdiv -silsubdiv -mark |
G3dOGL -st demos/data/club.s3d -key DmDeDbJ–
- reads a 500-face mesh, marks all edges with dihedral angle greater than 37 degrees as sharp,
- applies two steps of adaptive subdivision near these sharp edges, and
- shows the result flat-shaded (Dm), with edges (De), without backface culling (Db), spinning (J) somewhat slowly (--).
- reads the video (entirely into memory),
- uniformly scales the two spatial dimensions by a factor 1.5 using the Keys bicubic filter, and
- saves the new video.
VideoViewer demos/data/palmtrees_small.mp4 - -key =an
- reads the video (entirely into memory),
- reports statistics on the color channels,
- trims off 4 frames at the beginning,
- adds repeated copies of the last frames (with length 20% of the video),
- temporally scales the content by a factor of 1.5 and adjusts the framerate accordingly,
- spatially crops a centered rectangle with width 400 pixels and height 240 pixels,
- adjusts the color gamma,
- sets the output bitrate to 10 megabits/sec, and
- shows the result (
std::cin) together with the original video in an interactive viewer,
- with keypress = to scale the window size by 2, a to loop all (two) videos, and n to initially select the next (second) video.
This program reads a list of 3D (x, y, z) points assumed to be sampled near some unknown manifold surface,
and reconstructs an approximating triangle mesh. For example,
Filtermesh -genus -rmcomp 100 -fillholes 30 -triangulate -genus | tee distcap.recon.m |
G3dOGL -st demos/data/distcap.s3d -key DmDe
- reads the text file of points,
- reconstructs a triangle mesh assuming a maximum sample spacing (δ+ρ in paper) of 2% of the bounding volume,
- reports the genus of this initial mesh,
- removes all connected components with fewer than 100 triangle faces,
- fills and triangulates any hole bounded by 30 or fewer mesh edges,
- reports the genus of the modified mesh,
- saves it to a file, and
- displays it interactively from a specified viewpoint, with flat-shaded faces (Dm)
and mesh edges (De).
To show the progression of the Marching Cubes algorithm,
Filtera3d -split 30 | G3dOGL -key DCDb -st demos/data/distcap_backside.s3d -terse
- selects the ‘c’ (cubes) output stream,
- forces a frame refresh every 30 polygon primitive, and
- shows the result without display-list caching (DC) and without backface culling (Db).
To show a similar streaming reconstruction of the surface mesh,
Filtera3d -split 30 | G3dOGL demos/data/distcap.pts -key DCDb -st demos/data/distcap_backside.s3d -terse -input -key _Jo
- selects the default ‘m’ (mesh) output stream,
- converts the mesh to a stream of polygons, and
- shows the points and streamed reconstruction with a slow (_) automatic rotation (J) about the object frame (o).
The same program can also read a list of 2D (y, z) points to reconstruct an approximating curve:
Filtera3d -joinlines | tee curve1.a3d |
G3dOGL demos/data/curve1.pts -input -st demos/data/curve1.s3d
Given an initial mesh and a list of 3D points, this program optimizes both the mesh connectivity and
geometry to improve the fit, i.e. minimizing the squared distances from the points to the surface.
tee distcap.opt.m | G3dOGL -st demos/data/distcap.s3d -key DmDe
- reads the previously reconstructed mesh and the original list of points,
- applies an optimized sequence of perturbations to improve both the mesh connectivity and geometry,
- using a specified tradeoff between mesh conciseness and fidelity (crep=1e-4 yields a coarser mesh),
- saves the result to a file, and displays it interactively.
The input points can also be sampled from an existing surface, e.g.:
Meshfit -mfile demos/data/blob5.orig.m -file - -crep 1e-6 -simplify |
G3dOGL -st demos/data/blob5.s3d -key DmDe
To view the real-time fitting optimization,
- writes both the initial mesh and the stream of mesh modifications, and
- displays the changing mesh asynchronously with display-list caching disabled (DC).
This related program performs a similar optimization of a 1D polyline (either open or closed) to fit a set of 2D points. For example,
G3dOGL demos/data/curve1.pts -input -st demos/data/curve1.s3d
- reads the previously reconstructed polyline and the original list of points,
- optimizes vertex positions and simplifies the number of line segments according to some representation cost, and
- displays the result together with the original points.
In a subdivision surface representation, a coarse base mesh tagged with sharp edges defines a piecewise smooth surface as the limit of a subdivision process. Such a representation both improves geometric fidelity and leads to a more concise description.
Subdivfit -mfile - -file demos/data/distcap.pts -crep 1e-5 -csharp .2e-5 -reconstruct >distcap.sub0.m
- reads the previously optimized mesh and tags all edges with dihedral angle greater than 52 degrees as sharp,
- loads this tagged mesh and the original list of points,
- optimizes the mesh connectivity, geometry, and assignment of sharp edges to fit a subdivision surface to the points,
- with a representation cost of
1e-5per vertex and
.2e-5per sharp edge, and
- saves the resulting optimized base mesh to a file. (The overall process takes a few minutes.)
To view the result,
- reads the base mesh together with a second mesh obtained by applying two iterations of subdivision,
- shows the first mesh (N) with flat-shaded faces and edges (DmDe),
- waits for 5 seconds, and displays the second mesh (N) as a smooth surface without edges.
This program computes measures of differences between two meshes.
It samples a dense set of points from mesh1 and computes the
projections of each point onto the closest point on mesh2.
MeshDistanceloads the earlier results of mesh reconstruction and mesh optimization,
- computes correspondences from points sampled on each mesh to the other mesh (in both directions), and
- reports differences in geometric distance, color, and surface normals, using both L2 (rms) and L∞ (max) norms.
Given a mesh,
MeshSimplify applies a sequence of edge collapse operations to simplify it to a coarse base mesh while trying to best preserve the appearance of the original model. It supports many different simplification criteria, as well as face properties, edges tagged as sharp, and vertex and corner attributes (normals, colors, and texture
- reads the original mesh and randomly samples points over its surface,
- progressively simplifies it by examining point residual distances, while recording changes to a
- writes the resulting base mesh.
The next step is to reverse the sequence of stored edge collapse steps, i.e. forming a sequence of vertex splits:
We construct a concise progressive mesh by encoding the base mesh together with the sequence of vertex splits that exactly recover the original mesh:
The complete process from the original mesh to the progressive mesh
club.pm is implemented by the script call
Given a progressive mesh, we can interactively traverse its continuous levels of detail:
We can also define geomorphs between discrete levels of detail, e.g.
G3dOGL -st demos/data/club.s3d -key SPDeN -lightambient .5 -thickboundary 1 -video 101 - |
VideoViewer - -key m
- creates a geomorph between 2000 and 3300 faces, another between 3300 and 5000 faces, and similarly one more,
- shows these in a viewer with the level-of-detail slider enabled (S),
- selects all three geomorph meshes (P), enables mesh edges (De), selects the first mesh (N),
- records a video of 101 frames while moving the LOD slider, and
- shows the resulting video with mirror looping enabled (m).
This example displays a progressive mesh after truncating all detail below 300 faces and above 10000 faces:
G3dOGL -pm_mode - -st demos/data/standingblob.s3d
As an example of simplifying meshes with appearance attributes,