封口缝合本质是提取边界边、检测连通环、三角剖分填充;需手动实现三步,推荐earcut.hpp处理单环,注意顶点投影、去重与法线重建。

封口缝合的本质是构造边界环并三角剖分
网格切割后留下的“切口”本质是一组未闭合的边界边,缝合不是魔法操作,而是识别这些边界边构成的环(可能多个),再对每个环内部做三角剖分(Tessellation)或拉伸生成面片。C++ 里没有内置函数能“自动缝合”,必须自己走通这三步:提取边界 → 检测连通环 → 填充三角面。
- 边界边指只被一个三角形共享的边;遍历所有三角面,统计每条无向边出现次数,出现 1 次的就是边界边
- 用
std::unordered_map存边到邻接顶点映射,再用 DFS 或迭代追踪就能恢复出一个个首尾相接的顶点环 - 单环缝合可用耳切法(
earcut)或极角排序+扇形剖分;多环(如带孔)需区分内外环,得用约束 Delaunay 或先做环方向判定
用 earcut.hpp 快速实现单环三角化
如果你的切口是简单无自交环(绝大多数切割场景满足),earcut.hpp 是最轻量可靠的方案——头文件仅一个,不依赖第三方几何库,输出就是三角形索引数组。
- 输入必须是顺时针或逆时针有序顶点列表(
std::vector<:array>></:array>),注意 Z 坐标要统一(投影到 XY 平面再算,或用glm::vec2提取 UV/XY) - 不要直接喂三维点;先做平面拟合(如用 SVD 算法求最佳拟合平面),再把点投影过去,否则
earcut会因浮点误差失败 - 示例关键调用:
auto indices = mapbox::earcut<:size_t>(vertices_2d);</:size_t>,返回的是顶点索引序列,每三个一组构成新三角面
缝合后顶点去重与法线重建不能跳过
新生成的三角面顶点坐标大概率和原网格已有顶点不完全重合(浮点误差、投影偏移),直接拼接会导致裂缝或光照异常。
- 必须做顶点合并:遍历所有顶点,用
std::map+ 自定义比较(容差如1e-5f)归并空间距离近的点,并更新三角索引 - 缝合面的法线不能复用原网格法线;要对每个新三角面调用
glm::cross(v1-v0, v2-v0)计算法向量,再单位化 - 若原网格带顶点法线(如 smooth shading),缝合区域建议用平均周边面法线插值,而不是硬设为统一朝向
OpenMesh / CGAL 等库的缝合接口其实不省事
别被 OpenMesh::TriMesh::request_vertex_normals() 或 CGAL::Polygon_mesh_processing::stitch_boundary_edges() 的名字骗了——它们要么只处理拓扑缝合(边合并但不生成面),要么要求输入已是流形且边界严格匹配,对切割后的脏数据鲁棒性极差。
立即学习“C++免费学习笔记(深入)”;
-
CGAL::advancing_front_surface_reconstruction()看似能“补面”,但它假设点云密度均匀,切割边界点通常稀疏且线性分布,结果常是扭曲大面或失败 - 真正开箱即用的只有
libigl::copyleft::cgal::triangle_soup_to_polygon_mesh()配合libigl::boundary_loop(),但它强制依赖 CGAL 和 Eigen,编译链复杂度陡增 - 手写边界环提取 +
earcut组合,代码量不到 200 行,可控性强,调试时能精确看到哪一步断在边界不闭合或环方向反了


















