使用CGAL制作3D文字凹陷时触发断言错误问题排查
CGAL 5.5.2网格相减断言错误问题:切割网格未完全嵌入时触发异常
使用CGAL 5.5.2版本执行网格相减操作,为3D模型制作3D文字凹陷效果。当切割网格未完全嵌入目标模型(哪怕仅露出极小部分)时,会触发断言错误;若切割网格完全嵌入目标模型,或使用Blender默认立方体作为切割网格,操作可正常完成。
错误定位:该错误源于corefine_and_compute_boolean_operations函数调用Intersection_of_triangle_meshes仿函数时的check_no_duplicates检查。
核心实现代码
using ts_real = double; using ts_real3 = my_math_library::vec3<ts_real>; using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using SurfaceMesh = CGAL::Surface_mesh<Point>; std::optional<SurfaceMesh> subtract(SurfaceMesh& target, SurfaceMesh& cutter) { try { SurfaceMesh out; CGAL::Polygon_mesh_processing::corefine_and_compute_difference(target, cutter, out); return out; } catch (...) { return std::nullopt; } } // 网格变换方法 SurfaceMesh CopyAndTransformMesh(const ts_real3& translate_v, const ts_real3& rotate_v, const ts_real3& scale_v, SurfaceMesh const &input) { SurfaceMesh result = SurfaceMesh(input); // 复制网格 Transformation translate(CGAL::TRANSLATION, Vector_3(translate_v.x, translate_v.y, translate_v.z)); auto dmat3 = QuaternionFromEuler(rotate_v.x, rotate_v.y, rotate_v.z).as_mat3(); Eigen::Matrix3d rotation_matrix = eulerToMatrix(rotate_v.x, rotate_v.y, rotate_v.z); for (auto v : result.vertices()) { Point& p = result.point(v); p = Point(p.x() * scale_v.x, p.y() * scale_v.y, p.z() * scale_v.z); Eigen::Vector3d point(p.x(), p.y(), p.z()); point = rotation_matrix * point; p = Point(point[0], point[1], point[2]); p = translate(p); } return result; } // 通过ttf2mesh生成文字网格的方法 SurfaceMesh meshFromTTFMesh(ttf_mesh3d_t *mesh) { SurfaceMesh rv; std::vector<SurfaceMesh::Vertex_index> vertex_indices; vertex_indices.reserve(mesh->nvert); // 添加顶点 for (size_t i = 0; i < mesh->nvert; i++) { Point p(mesh->vert[i].x, mesh->vert[i].y, mesh->vert[i].z); vertex_indices.push_back(rv.add_vertex(p)); } // 添加面 for (size_t i = 0; i < mesh->nfaces; i++) { rv.add_face(vertex_indices[mesh->faces[i].v1], vertex_indices[mesh->faces[i].v2], vertex_indices[mesh->faces[i].v3]); } if (!CGAL::is_valid_polygon_mesh(rv)) { // 从未触发该分支 throw std::invalid_argument("TTF mesh is not valid polygon mesh"); } return rv; }
各向同性重网格化代码
inline SurfaceMesh isotropic_remesh(const SurfaceMesh &mesh, ts_real ratio = 0.05) { const auto bbox = ComputeSurfaceMeshBoundingBox(mesh); const ts_real target_edge_length = pow(length(bbox.size()), 1.0f/3.0f) * ratio; const uint32_t iterations = 3; SurfaceMesh rv = SurfaceMesh(mesh); std::vector<SM_edge_descriptor> border; CGAL::Polygon_mesh_processing::border_halfedges(faces(rv), rv, boost::make_function_output_iterator(halfedge2edge(rv, border))); CGAL::Polygon_mesh_processing::split_long_edges(border, target_edge_length, rv); CGAL::Polygon_mesh_processing::isotropic_remeshing( faces(rv), target_edge_length, rv, CGAL::parameters::number_of_iterations(iterations).protect_constraints(true) ); rv.collect_garbage(); return rv; }
触发的断言错误
CGAL error: assertion violation! Expression : enodes.size() == std::set<typename Exact_kernel::Point_3>(enodes.begin(), enodes.end()).size() File : ...\CGAL\include\CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_nodes.h Line : 316 Explanation: Refer to the bug-reporting instructions provided by CGAL
已尝试的修复方案
- 使用原始网格或细化网格
- 将网格保存为STL/OBJ/OFF格式后重新加载
- 使用自定义变换矩阵、Eigen或CGAL原生方法变换网格
内容的提问来源于stack exchange,提问作者malatindez
相关产品推荐
相关产品推荐

