Volume Cartographer 2.28.0
Flattening

Flattening algorithms

Volume Cartographer provides several mesh parameterization (flattening) algorithms through the volcart::texturing::AngleBasedFlattening class. All methods are implemented by the OpenABF library.

The flattening pipeline has two independent stages:

  1. Angle optimization (optional): ABF++ [sheffer2005abf] computes optimal interior angles that minimize distortion. This is recommended for most use cases.
  2. Parameterization: Maps the 3D mesh to 2D using either AngleBasedLSCM or HierarchicalLSCM [ray2003hierarchical].

Available methods

Method CLI name Description
ABF + LSCM (SparseLU) ABF Default. Fastest option. Uses a direct solver for the LSCM system. May run out of memory on very large meshes.
ABF + LSCM (CG) ABF with --solver CG Uses an iterative conjugate gradient solver. Lower memory than LU but generally slower than HLSCM.
ABF + HLSCM ABF-HLSCM Uses a cascadic multigrid LSCM solver. Slower than LU but significantly lower memory usage. Preferred over LSCM (CG) when memory is a concern.
LSCM (SparseLU) LSCM LSCM without ABF++ pre-optimization.
LSCM (CG) LSCM with --solver CG LSCM (CG) without ABF++ pre-optimization.
HLSCM HLSCM HierarchicalLSCM without ABF++ pre-optimization.
Note
The --solver option (--uv-solver in vc_render) controls the solver for both the ABF and standard LSCM steps. When using HierarchicalLSCM, the LSCM step always uses ConjugateGradient internally, but --solver still affects the ABF step if ABF is enabled.

Choosing a method

For most use cases, the default ABF + LSCM (SparseLU) is the best choice. It produces high-quality results and is the fastest option. However, the direct solver requires memory proportional to the mesh size, which can be a problem for very large meshes.

When memory is limited, ABF + HLSCM is the recommended alternative. It uses a cascadic multigrid approach that solves the LSCM system on a coarsened mesh hierarchy, warm-starting each level from the previous solution. This dramatically reduces peak memory usage compared to SparseLU while being faster than the standard CG solver.

ABF + LSCM (CG) is available as a fallback but is generally slower than HLSCM for comparable memory savings. Prefer HLSCM over LSCM (CG) unless you have a specific reason to use the standard iterative solver.

Omitting ABF++ (i.e. using LSCM, HLSCM, or LSCM-CG alone) is faster but produces lower quality results. This may be acceptable for previews or when the input mesh is already well-conditioned.

Note
When compiled with OpenMP support, the ConjugateGradient solver (used by both LSCM-CG and HLSCM) is multithreaded. Thread count can be controlled through the --threads option in vc_flatten_mesh and vc_render when the project is built with OpenMP support. See Eigen and multi-threading for more details.

CLI usage

Flattening is available through vc_flatten_mesh and vc_render:

# Default: ABF + LSCM with SparseLU
$ vc_flatten_mesh -i input.obj -o output.obj
# ABF + HLSCM (lower memory)
$ vc_flatten_mesh -i input.obj -o output.obj --method ABF-HLSCM
# HLSCM only (no ABF pre-optimization)
$ vc_flatten_mesh -i input.obj -o output.obj --method HLSCM
# ABF + LSCM with ConjugateGradient
$ vc_flatten_mesh -i input.obj -o output.obj --solver CG
# ABF + HLSCM with 4 threads
$ vc_flatten_mesh -i input.obj -o output.obj --method ABF-HLSCM --threads 4

In vc_render, the algorithm is selected with --uv-algorithm and the solver with --uv-solver (integer values):

# Default: ABF + LSCM (algorithm 0)
$ vc_render ... --uv-algorithm 0
# LSCM only (algorithm 1)
$ vc_render ... --uv-algorithm 1
# Orthographic Projection (algorithm 2)
$ vc_render ... --uv-algorithm 2
# ABF + HLSCM (algorithm 3)
$ vc_render ... --uv-algorithm 3
# HLSCM only (algorithm 4)
$ vc_render ... --uv-algorithm 4
# ABF + LSCM with ConjugateGradient solver
$ vc_render ... --uv-algorithm 0 --uv-solver 1

C++ usage

using namespace volcart::texturing;
// Default: ABF + LSCM with SparseLU
auto result = abf.compute();
// ABF + HLSCM
abf.setUseHLSCM(true);
result = abf.compute();
// HLSCM only (no ABF)
abf.setUseABF(false);
abf.setUseHLSCM(true);
result = abf.compute();
// ABF + LSCM with ConjugateGradient
abf.setUseABF(true);
abf.setUseHLSCM(false);
abf.setSolver(AngleBasedFlattening::Solver::ConjugateGradient);
result = abf.compute();
Texturing and parameterization algorithms and utilities library.

Measuring flattening error

A common way to measure flattening error is to observe the L2 and LInf stretch metrics introduced by Sander et al. [sander2001texture] . Volume Cartographer provides a method for calculating these metrics in the Texturing module. Once calculated, these metrics can also be plotted to an image:

#include <iostream>
#include <vc/texturing/FlatteningError.hpp> // LStretch
#include <vc/texturing/PPMGenerator.hpp> // GenerateCellMap
using namespace volcart;
using namespace volcart::texturing;
// Calculate error metrics
auto metrics = LStretch(mesh3D, mesh2D);
// Report the inverted global metrics (see note below)
metrics = InvertLStretchMetrics(metrics);
std::cout << "Global L2 stretch: " << metrics.l2 << "\n";
std::cout << "Global LInf stretch: " << metrics.lInf << "\n";
// Plot the per-face error
auto cellMap = GenerateCellMap(mesh2D, uvMap, height, width);
auto plots = PlotLStretchError(metrics, cellMap, ColorMap::Plasma);
std::vector< cv::Mat > PlotLStretchError(const LStretchMetrics &metrics, const cv::Mat &cellMap, ColorMap cm=ColorMap::Plasma, bool drawLegend=false)
Plot per-face L stretch error metrics.
LStretchMetrics LStretch(const ITKMesh::Pointer &mesh3D, const ITKMesh::Pointer &mesh2D)
Calculate the L2 and LInf stretch between a 2D and 3D mesh.
LStretchMetrics InvertLStretchMetrics(const LStretchMetrics &metrics)
Calculates the inverse LStretchMetrics plotting error relative to the 3D mesh.
auto GenerateCellMap(const ITKMesh::Pointer &mesh, const UVMap::Pointer &uv, std::size_t height, std::size_t width) -> cv::Mat
Generate a cell map image.
Volume Cartographer library

Flattening error can also be plotted when running vc_render:

$ vc_render ... --uv-plot-error error_plots.png

This will generate two images, error_plots_l2.png and error_plots_lInf.png, plotting the per-face L2 and LInf metrics respectively.

Note
The L2 and LInf stretch metrics represent the stretch from the 2D domain to the 3D domain. Thus, an LInf value of 0.5 indicates a flattening where a 3D unit vector is half the length of its corresponding 2D unit vector. This is the inverse of how stretch is generally considered in most of Volume Cartographer, where we are interested in the stretch introduced relative to the 3D domain. The VC applications dealing with these metrics will often invert the returned values to make reporting more intuitive.