8.网格剖分与轻量化

八、网格剖分与轻量化

核心概念区分: BRep(B‑Rep):参数化精确边界表达,存储曲线曲面方程,用于布尔、倒角、几何计算;不能直接给显卡渲染,也不能直接输出STL。 三角网格:离散的三角形面片,是近似表示;用于显卡显示、STL导出、仿真软件输入;网格丢失原始NURBS/解析曲面方程,网格不能拿来做布尔倒角。

OCCT中负责BRep转三角网格的核心类:BRepMesh_IncrementalMesh;网格数据存放在Poly_Triangulation。

8.1 为什么需要网格

BRep里面的Face保存的是Geom_Surface数学曲面,GPU显卡不认识NURBS、不认识解析曲面。显卡只接受顶点、三角形索引数据。

三个必须做网格离散化的业务场景:

  1. 三维视图显示(AIS可视化) AIS_Shape要渲染BRep实体,内部必须先生成三角网格;没有网格,拾取(点选面、边)也会失效。

    很多新手坑:创建完Solid直接Display,不做Mesh;视图看不见物体或者拾取完全无效。

  2. STL / OBJ 文件导出 STL格式只有三角面片,没有任何参数几何;导出STL必须先三角剖分。

  3. 仿真前置输入(CAE仿真) 有限元仿真软件输入是三角/四面体面片,需要把CAD实体离散成网格作为前置。

⚠️重要分界线: BRep:精确,可建模(布尔、圆角、分割),不能直接渲染 Poly网格:近似,用于显示/导出/仿真,不能做参数化建模

注意:BRepMesh_IncrementalMesh不会修改原始BRep模型! 三角网格是附加数据,挂在每一个TopoDS_Face上;原始Geom_Surface、BRep_TFace完好保留。删除网格不会损伤BRep实体。

8.2 三角化参数 BRepMesh_IncrementalMesh

#include <BRepMesh_IncrementalMesh.hxx>

TopoDS_Shape mySolid;

//构造剖分器
BRepMesh_IncrementalMesh meshTool(mySolid);

//=====三大核心参数=====
meshTool.SetLinearDeflection(0.5);   //线性偏差
meshTool.SetAngularDeflection(0.3);  //角度偏差(弧度)
meshTool.SetRelative(true);          //true=相对模型尺寸;false=绝对数值

meshTool.Perform();
if(meshTool.IsDone())
{
    //剖分完成,网格附加到各个Face上
}

三个关键参数详解

  1. SetLinearDeflection 线性偏差(距离偏差)

    控制:三角形面片与真实曲面之间允许的最大空间距离。

  • 数值越小:面片越贴近真实曲面,三角形数量变多,内存占用升高。
  • 数值越大:面片粗糙,三角形少,曲面看起来“棱角分明”。

举例:球体,如果线性偏差给很大,球体渲染出来变成多面体棱角球。

  1. SetAngularDeflection 角度偏差(单位:弧度)

    控制:两个相邻三角形法线之间最大允许夹角。 用于曲面弯曲大的地方自动加密网格。

  • 曲面曲率大(球面、圆柱圆角):角度阈值小,自动细分更多三角;
  • 平面:曲率为0,不需要细分,少量大三角形即可。

常用参考:0.3rad ≈17°;0.1rad≈5.7°。角度越小网格越密。

  1. SetRelative 相对/绝对模式
  • SetRelative(true):线性偏差是相对于模型包围盒尺寸的比例。 比如模型包围盒大小100,LinearDeflection=0.005;实际偏差=100*0.005=0.5。

    优势:不管模型放大缩小,网格精细度保持视觉一致,可视化场景最常用。

  • SetRelative(false):线性偏差为绝对距离值(和模型单位一致,mm)。

    STL导出给仿真,一般关闭相对,使用绝对偏差,保证物理精度。

❗常见踩坑:

  1. 只设置线性偏差,不设置角度偏差;圆角、球面部分网格会非常粗糙。两个参数要配合。
  2. 网格越密≠越好:网格数量爆炸会造成内存暴涨,视图卡顿。要在精度和性能做平衡。

补充:容差 BRepMesh_IncrementalMesh构造还可以传入一个公差值,用于处理模型微小缝隙,一般直接沿用BRep模型的整体容差。

8.3 三角化结果读取 Poly_Triangulation

剖分完成后,每个TopoDS_Face上面会附加网格数据对象:Poly_Triangulation。 使用工具类BRep_Tool读取Face上的三角剖分结果。

#include <BRep_Tool.hxx>
#include <Poly_Triangulation.hxx>

TopoDS_Face face;
//读取face上的三角网格
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face);
if(tri.IsNull())
{
    //没有网格,说明没有执行IncrementalMesh
}

Poly_Triangulation内部存储三块核心数据:

  1. 节点数组 Nodes():gp_Pnt数组,所有三角顶点坐标
  2. 三角索引数组 Triangles():每一个三角形是三个整数索引,指向Nodes里面顶点
  3. 法线数组 Normals():每个顶点的法向量(可选,用于光滑着色)

简单遍历示例:

Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face);

//顶点数量
Standard_Integer nbNodes = tri->NbNodes();
for(int i =1;i<=nbNodes;i++)
{
    gp_Pnt pt = tri->Node(i);
    gp_Vec normal = tri->Normal(i); //顶点法向
}

//三角形数量
Standard_Integer nbTri = tri->NbTriangles();
for(int i=1;i<=nbTri;i++)
{
    Poly_Triangle triFace = tri->Triangle(i);
    int v1,v2,v3;
    triFace.Get(v1,v2,v3);
    //v1 v2 v3 是顶点索引(从1开始!OCCT数组下标从1,不是0)
}

⚠️OCCT的Poly数组下标从1开始,不要直接丢给C++从零开始的数组忘记偏移。

重要: BRep_Tool::Triangulation(face)拿到的只是该单个Face的网格; 如果要导出整个Solid的全部三角,你需要TopExp_Explorer遍历全部Face,逐个取出Poly_Triangulation,把所有顶点、三角形索引拼接。

内存点:网格数据挂在Face;当原始BRep被销毁,网格跟着释放;如果BRep修改,旧网格失效,必须重新执行BRepMesh_IncrementalMesh重新剖分。

8.4 STL / OBJ 导出与轻量化

8.4.1 STL导出

OCCT内置StlAPI_Writer,底层内部自动调用BRepMesh_IncrementalMesh做三角剖分,再写STL文件。

#include <StlAPI_Writer.hxx>

StlAPI_Writer stlWriter;
stlWriter.SetASCIIMode(false); //false输出二进制STL;true输出文本STL
bool ok = stlWriter.Write(mySolid, "out.stl");

注意:StlAPI_Writer内部会自己做Mesh,但是你无法精细控制线性、角度偏差参数。 如果需要严格控制网格精度用于仿真,建议你先手动执行BRepMesh_IncrementalMesh设置好参数,再导出STL。

8.4.2 OBJ导出

OCCT没有开箱即用OBJ writer。一般两种方案:

  1. 遍历所有Face读取Poly_Triangulation,自己写文本输出顶点、三角索引,输出obj;
  2. 使用第三方封装库。

8.4.3 轻量化策略(两种完全不同轻量化,千万不要混淆)

类型A:BRep拓扑轻量化(保留参数几何,仍然可以建模)

  • 使用ShapeUpgrade_UnifySameDomain合并共面碎面,删除冗余拓扑;

  • 移除微小拓扑碎片;

    输出依然是BRep,可以继续布尔、倒角。不涉及三角网格。

类型B:网格轻量化(BRep不变,只对三角面片简化)

当Mesh生成之后三角数量巨大(几十万上百万三角,视图卡顿),需要对三角网格做简化,减少三角形数量。

OCCT原生没有网格简化API! 工程方案:

  1. 把Poly_Triangulation取出,导出到外部库(OpenMesh、CGAL)做网格减面简化;
  2. 简化完成后的网格,只能用于显示/导出,不能反向变回原始BRep参数模型。

工程实践最佳实践

  1. 后台算法运算层:永远使用原始BRep实体,不要拿网格做计算;
  2. UI显示层:生成一套合适精度三角网格用于渲染和拾取;
  3. 导出STL/仿真输出:重新跑一次BRepMesh,使用更高精度绝对偏差,输出高质量三角;不要复用视图的粗糙网格导出STL!

高频踩坑:直接拿视图显示用的低精度网格导出STL给仿真,得到质量很差的面片,仿真计算报错。

本章关键总结

  1. BRep是精确参数几何,显卡不能直接渲染,必须离散成三角网格;网格用于显示、STL、仿真;网格丢失曲面方程,不能做布尔倒角。
  2. BRepMesh_IncrementalMesh两大核心参数:线性偏差(距离)、角度偏差(曲率细分);支持相对/绝对模式。网格附加在TopoDS_Face上,不会修改原始BRep。
  3. Poly_Triangulation存储单张Face的网格数据:顶点、法线、三角形索引;注意OCCT下标从1开始;要遍历全部Face才能拿到整个形体完整网格。
  4. STL导出可以使用StlAPI_Writer;需要高精度就手动先做Mesh;OBJ一般自己写导出;OCCT没有内置网格减面简化。
  5. 区分两种轻量化:BRep拓扑清理(保留建模能力) vs 三角网格简化(仅用于显示导出)。

posted @ 2026-08-26 08:53  Drunker•L  阅读(65)  评论(0)    收藏  举报