Construct mesh export
SDF to triangle mesh export pipeline
Overview
The mesh export pipeline converts data-driven SDF scenes into triangle mesh files (STL, OBJ, PLY, VTK). The scene's field ā evaluated through the libeval Native JIT ā is the single source of truth: extraction, post-processing and the quality metrics all consume the same evaluator, so the exported mesh can be measured exactly against what was modelled.
Feature-preserving extraction and the post-process pipeline are specified in the construct-mesh-quality internal spec (content/doc/internal/specs/construct-mesh-quality/); this page is the reference summary.
Architecture
Scene snapshot (QVector<SDFNode>)
-> SdfSceneGraphBuilder -> eval::Graph
-> eval Backend::Native JIT (CPUFieldEvaluator; GPU batch path for chunks)
-> Φ(x) and āΦ(x) (IFieldEvaluator::evaluateWithGradient ā analytic
where the op tree is capable, FD-tetrahedron floor
everywhere else)
-> extractor: Marching Cubes | Dual Contouring | adaptive octree DC
-> post-process chain (optional): weld ā sdfProject ā coplanarMerge ā qemDecimate
-> mesh::Mesh<float> -> mesh::io::IORegistry -> STL/OBJ/PLY/VTK
Extractor family
Selected per export via ExportRequest.extractor (UI: the export dialog's Quality group):
| Extractor | Behaviour |
|---|---|
MarchingCubes |
Legacy baseline. Vertices constrained to grid edges ā sharp features alias into a staircase at any finite resolution. Chunked + parallel. |
DualContouring |
Uniform-grid Ju-2002 DC: one vertex per sign-change cell, positioned by a robust QEF over the cell's Hermite (Φ, āΦ) samples; bisection-refined edge crossings; exact chunk-seam welds via a shared global grid frame. |
DualContouringOctree |
One global octree over the domain with a conservative manifold-preserving collapse gate: triangles concentrate where the surface has detail (a box collapses to its exact 12-triangle mesh) and the output is guaranteed closed ā§ manifold ā§ orientable on the whole test corpus. |
Post-process stages
Declared as an ExportRequest.postprocess string list (also the bench definition's postprocess array); executed at the single buildAndSaveMesh hook. All stages preserve the watertight-manifold invariant ā mutating stages re-validate and restore their input on regression.
| Stage | Does |
|---|---|
weld[(tol)] |
Spatial-hash vertex weld of the extractor's triangle soup (auto-prepended when absent). |
sdfProject[(iters)] |
Newton-snaps vertices onto the exact zero level set x ā x ā Φ·āΦ/āāΦā² with tangential relaxation; crease vertices move only along their feature line, corners are pinned. |
coplanarMerge[(angleDeg)] |
Region-grows near-coplanar patches and retriangulates each from its boundary loop ā flat caps become fans. |
qemDecimate[(ratio)] |
Feature-aware quadric decimation: crease constraint planes + corner pinning keep the sharp edges extraction captured; link-condition collapses only. |
Quality metrics (SDF ground truth)
construct::bench::computeMeshMetrics measures a mesh against the same field it was extracted from ā no reference mesh:
- Surface error ā |Φ| at vertices, edge midpoints and face centroids (mean/p95/max).
- Feature error ā surface error restricted to the field-tagged high-curvature band (the cylinder-rim metric MC fails).
- Normal error ā angle between face normals and āΦ.
- Topology ā closed ā§ manifold ā§ orientable + boundary-edge count (
HalfedgeMeshpredicates); this triple is the export quality gate. - Triangle quality ā min-angle statistics.
The MeshExportBench runner records these per scene Ć pipeline definition into a lab::TestDB results database; browse it with the Mesh Lab activity or the mesh.bench.* OPAL tasks.
Source files
construct/eval/CPUFieldEvaluator.* ā libeval Native evaluator (+ analytic āΦ)
construct/eval/AnalyticGradient.* ā §AR-2.2 capability-gated analytic gradients
construct/mesh/MarchingCubes.* ā baseline extractor
construct/mesh/DualContouring.* ā uniform-grid DC + QEF
construct/mesh/Octree.* ā adaptive octree DC + manifold gate
construct/mesh/Qef.* ā robust QEF solver
construct/export/ExportPipeline.* ā async orchestrator + post-process hook
construct/export/PostProcess.* ā §BM-2 spec-string parser/runner
construct/bench/MeshExportBench.* ā corpus Ć definitions bench runner
construct/bench/MeshMetrics.* ā SDF-ground-truth metrics
construct/bench/MeshBenchWorker.* ā overnight batch worker, inputs and outputs by hash
construct/bench/MeshBenchJob.* ā submits a bench set and writes its outputs back
construct/ui/MeshExportConfigDialog.* ā export dialog (Quality group)
construct/ui/MeshLabActivity.* ā results browser
libmesh/mesh/process/⦠ā weld / SdfProjection / CoplanarMerge / QEM
Tests
testMeshExport,testConstructCliā pipeline end-to-end.testQef,testManifoldDCā DC extraction + the watertight-manifold corpus invariant.testSdfProjection,testFeatureQemā post-process stages + the post-decimate invariant.testMeshMetrics,testMeshExportBenchā metrics and the per-cell gates.construct-bench mesh-full --scenes <dir> --definitions <dir>ā the whole corpus x definitions matrix. It wastestMeshBenchFull, which asserted only that the bench ran and had to writeQTEST_FUNCTION_TIMEOUTinto its own environment to outlive QtTest's watchdog (no-environment-variables row T35).testMeshLabā batch worker ā results DB ā browser ā OPAL tasks.