You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:02:21