Triangle meshes in, clean triangle meshes out. RidgeForge is a small C++17 library for the unglamorous middle of a geometry pipeline: welding a scan that arrived as loose triangle soup, cutting it down to a triangle budget without rounding off the edges that matter, and reporting where a surface runs through itself.
No third-party dependencies. OpenMP is used if you have it and ignored if you don't. It builds a static library and, optionally, a one-header amalgamation and the rfmesh command-line tool.
Four things, and deliberately nothing else:
There is no scene graph, no material system, no renderer and no solver. If you need those, this is the wrong library.
Load a mesh, decimate to forty thousand triangles while keeping anything sharper than 35°, write it back - fifteen lines, no boilerplate:
// lod.cpp - c++ -std=c++17 lod.cpp -lridgeforge
#include <ridgeforge/mesh.hpp>
#include <ridgeforge/decimate.hpp>
#include <ridgeforge/io.hpp>
int main() {
auto loaded = rf::io::read("blade.ply");
if (!loaded) return 1; // Result<Mesh> is falsy on error
rf::Mesh mesh = std::move(*loaded);
rf::DecimateOptions opt;
opt.target_triangles = 40'000;
opt.preserve_boundary = true;
opt.ridge_angle_deg = 35.0f;
rf::Decimator{opt}.run(mesh);
return rf::io::write(mesh, "blade_lod1.ply") ? 0 : 2;
}
That is the API shape throughout: a plain options struct, an object built from it, one run() that mutates in place. See six more worked programs.
# CMakeLists.txt - needs CMake 3.20+
add_subdirectory(third_party/ridgeforge)
target_link_libraries(myapp PRIVATE RidgeForge::ridgeforge)
An installed copy works through find_package(RidgeForge 0.9 REQUIRED). Not using CMake? The rf_amalgamate target emits a single ridgeforge_all.hpp you compile directly - details on the build page.
These words are load-bearing. Stable: the signature holds until 2.0 and is covered by tests. Experimental: it worked on the meshes we tried and may change in any minor release. Partial: it does part of what the name says and the gap is written down.
| Component | Status | Since | Note |
|---|---|---|---|
Mesh, MeshView | stable | 0.4.0 | indexed triangles, 32-bit indices |
| I/O: OBJ, PLY, STL | stable | 0.5.0 | ascii and binary PLY |
Repair | stable | 0.6.0 | weld, orient, fill, prune |
Decimator | stable | 0.7.0 | quadric error, feature-aware |
RidgeExtractor | stable | 0.8.0 | ridge/valley polylines |
SelfIntersection::find | stable | 0.9.0 | exact, no tolerance |
SelfIntersection::resolve | experimental | 0.9.2 | fails on nested shells - RF-41 |
Remesher | experimental | 0.9.0 | isotropic only, no sizing field |
| Attribute carry-through | partial | 0.9.4 | normals and one UV set |
| glTF import/export | not planned | - | out of scope, see FAQ |
In: closed and open triangle meshes up to ~2³¹ vertices, deterministic output for a given input and option set, single process, optional OpenMP. Out: quad and polygon meshes, subdivision surfaces, NURBS, textures and materials, boolean/CSG, GPU and distributed execution. The boundary is firm; requests to move it land on the FAQ.
rf.MIT. Do what you like; keep the copyright line. Contributions go through the normal pull request flow and are taken under the same license.