DirectionalReMesher is a focused remeshing fork of Directional, the directional-field processing library developed by Amir Vaxman and collaborators.
It provides a practical C++20 implementation of the cross-field-guided remeshing pipeline described in Directional Field Synthesis, Design, and Processing.
The project converts triangle meshes into quad-dominant meshes whose edges follow a directional field defined across the surface. A field can be generated automatically from the input geometry or supplied by the user.
Compared with the original implementation, this fork adds:
- a reusable shared C++ library
- Python bindings
- an optional native command-line interface
- a shared C++ backend used by both CLIs
- multiple sparse integration solver backends
- expanded diagnostics and validation
- progress reporting for long-running operations
- additional mesh and field input/output formats
- Generate quad-dominant meshes from triangle meshes
- Align generated mesh edges with a cross-field
- Automatically calculate smooth 4-RoSy power fields
- Automatically calculate curvature-aligned cross-fields
- Remesh using a user-provided cross-field
- Import and export multiple mesh and field formats
- Use optimized sparse solvers for the integration stage
- Access the same remeshing pipeline through C++, Python, or the native CLI
-
Select an input triangle mesh
-
Choose how the guiding field will be obtained
- automatically generate a smooth power field
- automatically generate a curvature-aligned cross-field
- provide an existing 4-RoSy cross-field
-
Configure the target edge length and remeshing options
-
Generate the quad-dominant output mesh
The guiding field determines the preferred orientation of the generated mesh edges.
Use an automatically calculated field when you want a fully self-contained remeshing workflow.
This is the simplest option and works well for many smooth or moderately detailed meshes. Results depend on the quality of the input geometry, curvature estimation, boundaries, singularities, and selected parameters.
Use a supplied field when you need direct control over edge flow.
A carefully designed field can improve alignment around important features such as:
- ridges and valleys;
- anatomical or mechanical structures;
- boundaries;
- sharp features;
- intended deformation directions.
A neural model can predict a field from learned examples rather than relying only on geometric optimization.
The NeurCross project can be used to generate neural-assisted cross-fields. These fields may better capture high-level structural patterns on suitable meshes, but their quality depends on the model, training data, and similarity between the input mesh and the training examples.
Both auto-generated and neural-generated fields should still be validated before remeshing. They may require smoothing, constraint enforcement, or correction around singularities and boundaries.
- Start with a clean, manifold triangle mesh whenever possible.
- Remove duplicate vertices, degenerate faces, and disconnected fragments before remeshing.
- Use the lowest input face count that still preserves the required geometry.
- Very dense meshes increase field computation, integration, and mesh-generation time.
- Preserve important geometric features during simplification.
- Adjust the target length ratio to control the approximate size of generated faces.
- Use a custom field when automatic edge flow does not match the intended structure.
- Enable verbose output when diagnosing solver, topology, or field-integration failures.
- Compare multiple field-generation methods when automatic results are unsatisfactory.
Remeshing time depends on:
- the number of input vertices and faces;
- the number and placement of field singularities;
- the number of mixed-integer integration iterations;
- the selected sparse solver;
- the requested output resolution;
- the complexity of the generated mesh topology.
The progress percentage may occasionally pause or appear to advance unevenly. Some stages perform iterative refinement, repeated sparse solves, or topology cleanup whose cost cannot be predicted exactly in advance.
For faster processing:
- simplify unnecessarily dense input meshes;
- avoid requesting an excessively small target edge length;
- use an optimized sparse solver backend;
- test the workflow on a lower-resolution copy before processing the final mesh.
If remeshing fails:
- Run again with verbose output enabled.
- Check the input mesh for non-manifold edges, duplicate vertices, and degenerate faces.
- Try a less dense version of the mesh.
- Increase the target edge length.
- Try a different field-generation method.
- Inspect the generated field for discontinuities, poor boundary alignment, or excessive singularities.
- Supply a custom or neural-assisted field when automatic field generation is unsuitable.
Automatic field generation is intended to provide a useful default, but no single field-generation method is optimal for every mesh.
-
Direction field: A set of preferred directions defined across a surface. It guides how edges, curves, or quadrilateral faces should be oriented.
-
Cross-field: A direction field that provides four equivalent directions at each point on the surface, usually separated by 90 degrees. Because rotating the cross by 90 degrees produces the same field, it is well suited to quad remeshing.
-
Curvature-aligned cross-field: A cross-field whose directions follow the principal curvature directions of the surface. In simple terms, it tends to follow the natural bends, ridges, valleys, and flow of the shape.
-
Power field: A mathematical representation of a direction field in which rotationally equivalent directions are encoded as a single value. This makes the field easier to smooth and optimize.
-
4-power field: The power representation commonly used for a four-direction cross-field. Raising the direction representation to the fourth power makes directions that differ by 90 degrees equivalent.
-
Smooth power field: A power field optimized so that neighboring directions change gradually across the surface. It reduces sudden direction changes, except where singularities or strong geometric features require them.
-
Singularity: A point where the surrounding field cannot remain perfectly regular. Singularities are expected in cross-fields and often determine where the topology of the final quad mesh changes.
-
Field alignment: How closely the field follows a chosen target, such as surface curvature, feature lines, boundary edges, or user-specified directions.
-
Field smoothness: How gradually the field directions change from one part of the surface to another.
A Directional calculated cross-field is produced by geometric and numerical algorithms operating directly on the input mesh.
It typically:
- uses the mesh shape, curvature, boundaries, and optional constraints;
- solves an optimization problem to create a smooth and consistent field;
- follows mathematically defined behavior;
- produces predictable and reproducible results;
- may require more computation on large or complex meshes.
In simple terms:
Directional examines the surface geometry and calculates a field that is mathematically smooth and suitable for quad remeshing.
This is usually the most reliable option when geometric accuracy and reproducibility are important.
A neural-generated cross-field is predicted by a trained machine-learning model.
It typically:
- learns field patterns from example meshes and training data;
- predicts directions directly from mesh features;
- can be much faster after the model has been trained;
- may recognize structural patterns that are difficult to express with fixed rules;
- depends heavily on the quality and variety of its training data;
- may produce less predictable results on shapes unlike those seen during training.
In simple terms:
A neural model looks at the mesh and predicts what a good cross-field should look like based on examples it learned from.
This can be useful for fast initial estimates or for reproducing design patterns learned from a dataset. The predicted field may still need smoothing, constraint enforcement, or numerical correction before remeshing.
A power field is not necessarily a separate source of field directions. It is primarily a different mathematical representation of a directional or neural-generated field.
It typically:
- removes ambiguity between directions that are rotationally equivalent;
- makes smoothing and optimization easier;
- allows a four-direction cross-field to be represented as one continuous mathematical quantity;
- must be converted back into explicit cross directions before visualization or remeshing.
In simple terms:
A power field is a convenient mathematical encoding of a cross-field, rather than a different kind of geometric guidance.
For a four-direction cross-field, the fourth-power representation treats all four arms of the cross as the same orientation.
| Field type | How it is produced | Main advantage | Main limitation |
|---|---|---|---|
| Directional calculated cross-field | Numerical optimization based on mesh geometry | Reliable, reproducible, and geometrically grounded | Can be computationally expensive |
| Neural-generated cross-field | Prediction from a trained neural network | Fast and capable of learning complex patterns | Quality depends on training data and may require correction |
| Power field | Mathematical encoding of another direction field | Easier to smooth, optimize, and store | Not directly the final visible cross-field |
| Curvature-aligned cross-field | Built or constrained to follow surface curvature | Follows natural ridges, valleys, and shape flow | Curvature can be noisy or ambiguous on flat and irregular areas |
| Smooth power field | Power field after smoothness optimization | Produces gradual and coherent direction changes | Excessive smoothing can weaken important features |
Think of a quad-remeshing field as a set of compass crosses placed across the surface.
- A Directional calculated cross-field places and adjusts those crosses using geometric rules and numerical optimization.
- A neural-generated cross-field predicts where the crosses should point based on previously learned examples.
- A power field is the mathematical format used to represent those crosses without having to distinguish between their four equivalent arms.
- A curvature-aligned field turns the crosses so they follow the natural bends and features of the surface.
- A smooth field ensures neighboring crosses rotate gradually rather than changing direction abruptly.
The top-level project can build:
directional— shared C++ library_directional— Python extension moduledirectional_cli— optional native executable installed asdirectionaldirectional_cli_backend— shared C++ command implementation used by both CLIs
The Python console script and native executable intentionally expose the same commands and option parsing through the C++ CLI backend.
- CMake 3.21 or newer
- C++20-capable compiler
- Git submodules initialized, including Eigen
- Python only when building Python bindings or invoking
setup.py
Python 3.13 is verified in this repository. Install the build dependencies with:
python -m pip install setuptools wheel pybind11For PEP 517 builds, install any additional requirements declared by the project build configuration or disable build isolation when the active environment already contains them.
Eigen is required and included as a repository submodule.
git submodule update --init --recursiveGMP is optional and enables the preferred exact-arithmetic implementation.
- CMake option:
DIRECTIONAL_ENABLE_GMP - Default:
ON - MSVC builds can auto-install it when it is not already available
- Other platforms should provide GMP and GMPXX through the system or toolchain
When GMP cannot be found, CMake emits a warning and continues without GMP.
DirectionalReMesher supports three optional integration solver backends:
- Intel oneMKL PARDISO
- NVIDIA cuDSS
- SuiteSparse / UMFPACK
Only one backend is enabled in a build. If more than one is requested, both CMake and setup.py emit a warning and select the first available request in this fixed order:
PARDISO > CUDSS > SUITESPARSE
Relevant CMake options:
DIRECTIONAL_ENABLE_PARDISO=ON|OFF
DIRECTIONAL_ENABLE_CUDSS=ON|OFF
DIRECTIONAL_ENABLE_SUITESPARSE=ON|OFF
CUDSS_ROOT=<path>
CMake defaults are:
PARDISO=OFF
CUDSS=OFF
SUITESPARSE=ON
The current setup.py defaults request all three backends and therefore resolve to PARDISO unless overridden.
PARDISO uses Intel oneMKL and is the highest-priority backend. On supported MSVC builds, the dependency logic can install oneMKL automatically. Required runtime modules are copied beside the native library, native CLI, and Python extension during build and install.
cuDSS requires an NVIDIA cuDSS installation and the imported CMake target CUDSS::cudss. Set CUDSS_ROOT when automatic discovery is insufficient.
Example:
cmake -S . -B build\cudss `
-DDIRECTIONAL_ENABLE_PARDISO=OFF `
-DDIRECTIONAL_ENABLE_CUDSS=ON `
-DDIRECTIONAL_ENABLE_SUITESPARSE=OFF `
-DCUDSS_ROOT="C:\Program Files\NVIDIA cuDSS\v0.8"SuiteSparse is the default CMake backend. Supported MSVC builds can auto-install it when necessary. Other platforms should provide a usable SuiteSparse package or CMake configuration.
| Option | Default | Purpose |
|---|---|---|
BUILD_PYTHON |
OFF |
Build the Python extension |
DIRECTIONAL_BUILD_CLI |
OFF |
Build the native CLI executable |
DIRECTIONAL_ENABLE_GMP |
ON |
Enable GMP exact arithmetic |
DIRECTIONAL_ENABLE_SUITESPARSE |
ON |
Request SuiteSparse |
DIRECTIONAL_ENABLE_PARDISO |
OFF |
Request Intel oneMKL PARDISO |
DIRECTIONAL_ENABLE_CUDSS |
OFF |
Request NVIDIA cuDSS |
CUDSS_ROOT |
empty | cuDSS installation root |
CMAKE_INSTALL_PREFIX |
platform default | Installation destination |
cmake -S . -B build\standalone `
-DCMAKE_INSTALL_PREFIX="$PWD\build\standalone\install" `
-DBUILD_PYTHON=OFF `
-DDIRECTIONAL_BUILD_CLI=OFF `
-DDIRECTIONAL_ENABLE_GMP=ON `
-DDIRECTIONAL_ENABLE_PARDISO=OFF `
-DDIRECTIONAL_ENABLE_CUDSS=OFF `
-DDIRECTIONAL_ENABLE_SUITESPARSE=ON
cmake --build build\standalone --config Release --target directional
cmake --install build\standalone --config Releasecmake -S . -B build\pardiso `
-DCMAKE_INSTALL_PREFIX="$PWD\build\pardiso\install" `
-DBUILD_PYTHON=OFF `
-DDIRECTIONAL_ENABLE_PARDISO=ON `
-DDIRECTIONAL_ENABLE_CUDSS=OFF `
-DDIRECTIONAL_ENABLE_SUITESPARSE=OFF
cmake --build build\pardiso --config Release --target directional
cmake --install build\pardiso --config Releasecmake -S . -B build\native-cli `
-DCMAKE_INSTALL_PREFIX="$PWD\build\native-cli-release" `
-DBUILD_PYTHON=OFF `
-DDIRECTIONAL_BUILD_CLI=ON `
-DDIRECTIONAL_ENABLE_PARDISO=ON
cmake --build build\native-cli --config Release --target directional_cli
cmake --install build\native-cli --config ReleaseThe installed executable is normally:
<install-prefix>/bin/directional.exe
Run:
directional --help
directional infopython -m pip install pybind11
$pybind11Dir = python -m pybind11 --cmakedir
cmake -S . -B build\python `
-DCMAKE_INSTALL_PREFIX="$PWD\build\python\install" `
-DBUILD_PYTHON=ON `
-DDIRECTIONAL_BUILD_CLI=OFF `
-Dpybind11_DIR="$pybind11Dir" `
-DDIRECTIONAL_ENABLE_PARDISO=ON
cmake --build build\python --config Release --target _directional
cmake --install build\python --config ReleaseThe extension and Python package files are installed beneath:
build/python/install/directional/
find_package(Directional CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE Directional::directional)For a nonstandard installation prefix:
cmake -S . -B build `
-DCMAKE_PREFIX_PATH="D:\path\to\DirectionalReMesher\build\standalone\install"setup.py forwards build features to CMake and uses the same solver-selection priority.
--enable-gmp / --disable-gmp
--enable-suitesparse / --disable-suitesparse
--enable-pardiso / --disable-pardiso
--enable-cudss / --disable-cudss
--build-cli / --no-build-cli
python setup.py standaloneDefault paths:
build tree: build/standalone/
install tree: build/standalone/install/
Build the library and native CLI together:
python setup.py standalone --build-cliSelect a solver explicitly:
python setup.py standalone `
--enable-pardiso `
--disable-cudss `
--disable-suitesparse `
--build-cliBuild the extension:
python setup.py build_extBuild a wheel:
python setup.py bdist_wheelPass feature flags through build_ext when creating a wheel:
python setup.py build_ext `
--enable-pardiso `
--disable-cudss `
--disable-suitesparse `
bdist_wheelBuild and package the native executable with the wheel:
python setup.py build_ext --build-cli bdist_wheelWhen enabled, the installed native CLI and its runtime dependency closure are packaged beneath:
directional/bin/
The Python console script remains available as directional and forwards commands to the same C++ backend through the extension module.
The custom build backend accepts short and namespaced configuration keys.
| Short key | Namespaced key | Environment variable |
|---|---|---|
enable-gmp |
directional.enable-gmp |
DIRECTIONAL_ENABLE_GMP |
enable-suitesparse |
directional.enable-suitesparse |
DIRECTIONAL_ENABLE_SUITESPARSE |
enable-pardiso |
directional.enable-pardiso |
DIRECTIONAL_ENABLE_PARDISO |
enable-cudss |
directional.enable-cudss |
DIRECTIONAL_ENABLE_CUDSS |
build-cli |
directional.build-cli |
DIRECTIONAL_BUILD_CLI |
Boolean values accept:
1, 0, on, off, true, false, yes, no
python -m pip install . --no-build-isolationpython -m pip wheel . `
--no-deps `
--no-build-isolation `
-Cdirectional.enable-pardiso=true `
-Cdirectional.enable-cudss=false `
-Cdirectional.enable-suitesparse=falsepython -m pip wheel . `
--no-deps `
--no-build-isolation `
-Cdirectional.build-cli=true$env:DIRECTIONAL_ENABLE_GMP = "1"
$env:DIRECTIONAL_ENABLE_PARDISO = "1"
$env:DIRECTIONAL_ENABLE_CUDSS = "0"
$env:DIRECTIONAL_ENABLE_SUITESPARSE = "0"
$env:DIRECTIONAL_BUILD_CLI = "1"
python -m pip wheel . --no-build-isolationThe legacy GMP environment variable DIRECTIONAL_DIRECTIONAL_ENABLE_GMP remains accepted as an alias.
Both the Python command and native executable support the same command set:
directional info
directional cross-field <input.obj|input.off> <output-field> [options]
directional convert-field <input-field> <output-field> [options]
directional remesh <input.obj|input.off> <output.obj|output.off> [options]
directional --version
directional --help
The Python module form is also supported:
python -m directional --help| Format | Extensions | Description |
|---|---|---|
crossfield |
.vec, .txt |
Alpha and beta vectors; six values per row |
rosy |
.rosy |
Count/degree header followed by one alpha vector per face |
rawfield |
.rawfield |
Degree/count header followed by 3 × degree values per face |
directional cross-field input.obj output.rosy `
--output-format rosy `
--singularities output.singsOptions:
--output-format <auto|crossfield|rosy|rawfield>
--no-normalize-directions
--no-normalize
--no-matching
--singularities <path>
--diagnostics-prefix <prefix>
--verbose
directional convert-field input.rosy output.txt `
--input-format rosy `
--output-format crossfield `
--mesh input.objOptions:
--input-format <auto|crossfield|rosy|rawfield>
--output-format <auto|crossfield|rosy|rawfield>
--mesh <input.obj|input.off>
--degree <2|4>
The mesh is required when conversion must reconstruct beta directions from face normals.
Compute a cross field automatically and remesh:
directional remesh input.obj output.obj --length-ratio 0.02Use an existing field:
directional remesh input.obj output.off `
--field input.rosy `
--field-format rosy `
--length-ratio 0.02Options:
--field <path>
--field-format <auto|crossfield|rosy|rawfield>
--raw-field <path>
--primary-directions <path>
--secondary-directions <path>
--length-ratio <value>
--no-integral-seamless
--round-seams
--no-normalize-directions
--diagnostics-prefix <prefix>
--verbose
Without --verbose, long-running remeshing stages use in-place top-level progress reporting. With --verbose, detailed phase timing and solver diagnostics are printed as regular log lines.
The extension exposes the headless remeshing API, including:
directional.RemeshOptions
directional.RemeshResult
directional.remesh_from_cross_field(...)
directional.remesh_from_raw_cross_field(...)
Minimal example:
import numpy as np
import directional
vertices = np.array(
[
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
],
dtype=np.float64,
)
faces = np.array([[0, 1, 2]], dtype=np.int32)
primary_directions = np.array([[1.0, 0.0, 0.0]], dtype=np.float64)
options = directional.RemeshOptions()
result = directional.remesh_from_cross_field(
vertices,
faces,
primary_directions,
options,
)
print(result.success)Install test dependencies and run the Python tests:
python -m pip install -e .[test] --no-build-isolation
python -m pytestFor native validation, configure and build the desired CMake targets, then run any CTest targets included by the current source tree:
ctest --test-dir build\standalone -C Release --output-on-failureA native install typically contains:
bin/ directional executable and runtime DLLs
lib/ directional import/static artifacts
include/ Directional and Eigen headers
lib/cmake/Directional/ exported CMake package
A Python install contains:
directional/
__init__.py
_directional*.pyd|so
bin/ optional native CLI and runtime files
Use direct CMake when:
- embedding DirectionalReMesher into another C++ project
- producing an installed
find_package-compatible package - controlling dependency discovery and runtime deployment directly
Use setup.py when:
- iterating locally on the Python extension
- building the standalone library through a Python command
- building the optional native CLI alongside the extension
Use PEP 517 / pip when:
- producing standard wheels
- integrating with build automation
- controlling solver and CLI options through
--config-settings
- Only one integration solver backend is compiled into a build.
- The selection priority is always PARDISO, then cuDSS, then SuiteSparse.
- The C++ package exports
Directional::directional. - Python wheels are platform-specific because they contain a compiled extension.
- PARDISO builds deploy the oneMKL runtime modules needed by
mkl_rtbeside installed binaries. - The native CLI and Python CLI share the same C++ implementation; command behavior should remain consistent between them.
Original source: avaxman/Directional
If you use this project in research, cite the original Directional work:
@misc{Directional,
author = {Amir Vaxman and others},
title = {Directional: A library for Directional Field Synthesis, Design, and Processing},
doi = {10.5281/zenodo.3338174},
url = {https://doi.org/10.5281/zenodo.3338174}
}