Mesh Processing Library
Overview
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 history
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 msbuild
command.
The code can also be compiled using gcc
and 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 libpng
and 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.
Code compilation
Compiling using the Microsoft Visual Studio IDE
Open the distrib.sln
file and build the solution (typically using the “ReleaseMD - x64
” build configuration).
Executables are placed in the bin
, bin/debug
, bin/Win32
, or bin/Win32/debug
directory, depending on the build configuration (64-bit versus 32-bit, and release versus debug).
Compiling using msbuild
Set the appropriate environment variables and run msbuild
, e.g.:
(Some alternatives are to set platform
to Win32
, or configuration
to DebugMD
, Release
, or Debug
; here MD
stands for multithreaded DLL.)
Executables are placed in the same target directory as in the IDE.
Compiling using GNU make
The 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 bin/win
):
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 bin/unix
):
make CONFIG=unix -j Filtermesh
To build all program and run all demos using the Cygwin gcc
compiler:
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 Makefile_defs*
files.
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
Demos
After the code is compiled, the demos can be run as follows.
In Windows, create and view all the results using the batch
scripts
In Unix or Windows Cygwin, either run the bash
scripts
or alternatively (and faster), invoke make
to create all results in parallel and then view them sequentially:
Filter programs
All programs recognize the argument --help
(or -?
) to show their many options.
The programs Filterimage
, Filtermesh
, Filtervideo
,
FilterPM
, and 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
std::cout
(unless-nooutput
is specified).
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
std::cerr
), and - 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.
The command
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 (--).
The command
- 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.
The command
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 (
-
forstd::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.
Surface reconstruction
Recon
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
Meshfit
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.
For example,
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).
Polyfit
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.
Subdivfit
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-5
per vertex and.2e-5
per 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.
MeshDistance
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.
MeshDistance
loads 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.
Mesh simplification
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 uv
coordinates).
For example,
- reads the original mesh and randomly samples points over its surface,
- progressively simplifies it by examining point residual distances, while recording changes to a
*.prog
file, and - 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,