OCCT 中 STEP 模型网格化算法详解:BRepMesh 原理、参数与实践
前言
STEP(ISO 10303)是 CAD 领域最通用的模型交换格式,它保存的是精确的边界表示(B-rep, Boundary Representation)——解析曲面、NURBS、精确的拓扑关系。但在实际工程中,GPU 渲染、3D 打印(STL)、CAE 前处理等下游应用需要的不是精确曲面,而是三角网格(Triangle Mesh)。把 B-rep 转换成三角网格的过程就叫做网格化 / 镶嵌(Tessellation / Meshing)。
OpenCASCADE Technology(OCCT)内置了成熟的网格化组件 BRepMesh,核心类是 BRepMesh_IncrementalMesh。本文将系统讲解:
- BRepMesh 的两阶段算法原理(边离散化 + 面三角化),以及它如何保证水密性;
IMeshTools_Parameters中每个参数的含义与默认值;- 从读取 STEP 到导出 STL 的完整工程代码;
- 不同场景下的调参实践与常见问题排查。
一、快速上手:最小可用代码(TL;DR)
如果只想立刻把 STEP 变成 STL,下面 20 行就是全部(OCCT 7.6+):
1 |
|
几个必须记住的结论:
- 必须先网格化再导出:
RWStl只写出已有的三角剖分,不会自动网格化,跳过第 3 步会得到一个空 STL; - 核心参数只有两个:
Deflection(弦高误差,控制曲面逼近精度)和Angle(角度误差,控制折线平滑度); - Deflection 与模型单位一致(STEP 通常是毫米),经验值取模型包围盒对角线的 0.1%(即
对角线 × 0.001); - 想换参数重新网格化,先调用
BRepTools::Clean(shape)清除旧网格,否则增量式算法会复用旧结果。
二、为什么需要网格化:从 B-rep 到三角网格
| 特性 | B-rep(STEP 中的表示) | 三角网格 |
|---|---|---|
| 几何精度 | 精确(解析曲面 / NURBS) | 近似(平面三角形逼近,误差可控) |
| 拓扑信息 | 完整(Solid/Shell/Face/Edge/Vertex) | 通常无(STL 就是”三角形汤”) |
| 数据量 | 小 | 大(精度越高三角形越多) |
| 典型消费者 | CAD 建模内核 | GPU 渲染管线、切片软件、部分 CAE 前处理 |
| 求交/布尔运算 | 精确、可靠 | 只能近似 |
网格化的本质是一个有损压缩问题:用一组平面三角形去逼近光滑曲面,同时把逼近误差控制在给定阈值内。误差阈值选多大、三角形放多少,就是 BRepMesh 全部参数要回答的问题。
三、BRepMesh 网格化算法原理(BRepMesh_IncrementalMesh)
3.1 总体流程
BRepMesh 的网格化分为两个串行阶段:
- 边离散化(Edge Discretization):把每条
TopoDS_Edge的三维曲线离散成一条折线(Poly_Polygon3D); - 面三角化(Face Triangulation):以各条边的离散点为边界约束,在每个面的 UV 参数域内做三角剖分,再映射回三维空间,得到挂在每个
TopoDS_Face上的Poly_Triangulation。
两个阶段都由同样的两类误差约束控制:线性偏差(Deflection)和角度偏差(Angle)。
3.2 第一阶段:边离散化
对一条参数曲线
条件一:弦高误差(Chordal / Linear Deflection)。曲线上任意一点到对应弦(线段)的最大距离不超过 Deflection:
条件二:角度误差(Angular Deflection)。相邻两段弦的切向夹角不超过 Angle(弧度):
两个条件是同时生效、取更严格者的:曲率大的区域由 Angle 主导加密,缓弯但弦长过大的区域由 Deflection 主导加密。实现上,OCCT 使用 GCPnts 包中的切向偏差类算法(如 GCPnts_TangentialDeflection、GCPnts_QuasiUniformDeflection)在曲线上自适应取点。
3.3 第二阶段:面三角化
边离散完成后,每个面的处理流程是:
- 收集边界约束:把构成该面各 Wire 的边离散点(含方向信息)作为约束多边形;
- 在 UV 参数域做约束 Delaunay 三角化(Constrained Delaunay Triangulation):OCCT 在面的二维参数空间
中插入边界点并构建满足 Delaunay 空圆性质的三角剖分,边界边作为不可翻转的约束边; - 插入内部点(可选):若
InternalVerticesMode = true(默认),在面内部按误差要求补充采样点,避免大平面出现狭长三角形; - 表面偏差控制(可选):若
ControlSurfaceDeflection = true(默认),算法检查每个三角形与真实曲面的距离,超过Deflection的区域会插入新点加密; - 映射回三维:每个 UV 节点经曲面求值
得到三维坐标,存入Poly_Triangulation(同时保留 UV 坐标,供纹理或参数域查询使用)。
3.4 水密性(Watertight)为什么天然成立
B-rep 中相邻两个面共享同一条 TopoDS_Edge(同一 TShape)。由于每条边只在第一阶段离散一次,两个面在公共边界上拿到的离散点完全一致,三角化后边界上的节点天然一一对应,不会出现裂缝(T-junction / crack)。这是 BRepMesh 相对”逐面独立网格化”方案的核心优势,也是导出的 STL 能直接用于 3D 打印切片的原因。
3.5 增量式(Incremental)的含义
网格化结果缓存在拓扑数据结构上(TopoDS_TFace)。再次调用 BRepMesh_IncrementalMesh 时,如果已有网格满足当前精度要求,算法会直接跳过该面——这对交互式应用很友好,但也带来一个经典坑:改了参数重新网格化却”没效果”。解决办法是先清理:
1 |
|
四、核心参数详解(IMeshTools_Parameters)
OCCT 7.6 起推荐使用 IMeshTools_Parameters 统一传参(旧式构造函数 BRepMesh_IncrementalMesh(shape, deflection, isRelative, angle, isInParallel) 仍然可用,内部就是转发到它)。各字段含义与默认值如下:
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
Deflection | Real | 0.001 | 弦高误差上限,与模型同单位。网格精度的主开关 |
Angle | Real | 0.5 rad(≈28.6°) | 相邻线段/三角形法向夹角上限,控制平滑度 |
AngleInterior | Real | -1(= 用 Angle) | 面内部区域的角度误差上限,可与边界分开设置 |
DeflectionInterior | Real | -1(= 用 Deflection) | 面内部区域的弦高误差上限,可与边界分开设置 |
Relative | Boolean | false | 为 true 时各边按自身长度 × Deflection 计算误差(相对模式) |
InParallel | Boolean | false | 多线程并行网格化,装配体大模型建议开启 |
MinSize | Real | Precision::Confusion() | 网格单元最小尺寸下限,防止数值退化 |
InternalVerticesMode | Boolean | true | 是否在面内部插入采样点(提高三角形质量) |
ControlSurfaceDeflection | Boolean | true | 是否按曲面真实偏差自适应加密面内网格 |
CleanModel | Boolean | true | 清理模型已有网格数据的策略开关 |
AdjustMinSize | Boolean | false | 是否允许按面的尺寸自动放宽 MinSize |
AllowQualityDecrease | Boolean | false | 困难区域允许适度放宽误差以完成网格化 |
MeshAlgo | Integer | -1(默认内核) | 面三角化算法选择:-1 默认 / 0 Watson / 1 Delaunay |
下面对最重要的几个参数展开说明。
4.1 Deflection:弦高误差(精度主开关)
- 意义:三角形(或弦)与真实曲面之间允许的最大距离。
- 量纲:与模型单位一致(STEP 一般是 mm)。
Deflection = 0.1对毫米模型就是 0.1 mm。 - 经验公式:
Deflection ≈ 包围盒对角线 × 0.001(高质量可视化可到 0.0001,预览可放宽到 0.005)。 - 副作用:Deflection 减半,曲面区域三角形数量大约变为 4 倍(面积平方关系),时间与内存同步上涨。不要无脑设成机器精度。
4.2 Angle:角度误差(平滑度开关)
- 意义:相邻离散段方向变化的上限(弧度)。对圆/圆柱等恒曲率几何体起决定性作用。
- 直觉换算:一段圆弧被离散后,每段对应的圆心角不超过
Angle。默认值 0.5 rad ≈ 28.6°,意味着整圆最少被离散成约 13 段——这就是”圆柱看起来像多边形”的直接原因。 - 常用取值:渲染 0.5,精细可视化 0.25,出口级质量 0.1(整圆约 63 段)。
4.3 Relative:相对误差模式
Relative = true 时,每条边按 边长 × Deflection 确定自己的误差阈值。效果是大特征粗、小特征相对细,适合尺寸跨度极大的装配体。但注意此时 Deflection 不再具有绝对单位含义,调试直觉会差一些,单零件一般保持 false。
4.4 InternalVerticesMode 与 ControlSurfaceDeflection
InternalVerticesMode = true(默认)会在面内部补点,显著改善大曲面上的三角形形状(避免狭长三角形),对后续做变形、纹理贴图、FEA 前处理都有益;纯渲染且追求最少三角数时可以关掉。ControlSurfaceDeflection = true(默认)让算法主动校验”三角形到曲面”的真实偏差并加密,保证Deflection在面内部(而不只是边界附近)也成立。关闭后速度略快但精度承诺变弱,一般不建议关。
4.5 AngleInterior / DeflectionInterior:内外差别化精度
默认值 -1 表示与全局 Deflection / Angle 相同。把它们设成比全局值更大,可以实现”边界密、内部疏”的网格——边界决定零件轮廓和装配配合,内部大平缓区域没必要同等密度,这是降低三角数的高级手段。
4.6 InParallel:多线程
InParallel = true 后面级网格化按面并行。对几十上百个面的装配体提速明显;单个简单零件收益有限。OCCT 的并行基于其自身的 OSD_Parallel,不需要额外依赖。
五、完整工程示例:STEP → 网格化 → STL
下面是一个可直接编译的完整程序,包含:STEP 读取、按包围盒自动计算 Deflection、清理旧网格、并行网格化、网格规模统计、二进制 STL 导出。
1 |
|
对应的 CMakeLists.txt(链接库按依赖关系列出):
1 | cmake_minimum_required(VERSION 3.10) |
六、参数选择实践指南
| 场景 | Deflection(相对包围盒对角线) | Angle | 其他建议 |
|---|---|---|---|
| 实时渲染 / 网页预览 | 0.1% ~ 0.5% | 0.5 | 可关闭 InternalVerticesMode 减少三角数 |
| 高质量可视化 / 截图 | 0.01% ~ 0.05% | 0.25 | — |
| 3D 打印 / STL 导出 | 0.05% 且不大于打印层精度(如 0.05 mm) | 0.25 ~ 0.1 | 误差小于喷嘴/层厚精度即可,再小只是浪费 |
| CAE 前处理 | 0.01% 或按物理公差 | 0.1 | 保持 InternalVerticesMode = true |
| 大型装配体 | 用 Relative = true 或分级设置 | 0.5 | 开启 InParallel |
几条实用经验:
- 先用默认值跑一遍(
Deflection=0.001,Angle=0.5),看三角数和视觉效果再向需要的方向调; - Deflection 与用途对齐,而不是与机器精度对齐:3D 打印超过喷嘴精度、渲染超过亚像素,都没有意义;
- 圆柱/孔类特征”变多边形”先调 Angle 再调 Deflection——恒曲率几何由角度误差主导;
- 三角数暴涨时优先检查是否有微小碎面(STEP 转换常见问题),必要时用
ShapeUpgrade_UnifySameDomain先做模型清理。
七、常见问题 FAQ
Q1:为什么导出的 STL 文件是空的(0 字节或只有文件头)?
RWStl::WriteBinary / WriteAscii 只负责把已经存在的三角剖分写出来,本身不做网格化。读取 STEP 后必须先调用 BRepMesh_IncrementalMesh,否则 shape 上没有任何三角形可写。
Q2:调小 Deflection 重新网格化,结果完全没有变化?
BRepMesh 是增量式算法:已有网格若满足新参数要求就会被保留。换参数前显式清理:
1 | BRepTools::Clean(shape); |
Q3:相邻面之间出现裂缝怎么办?
理论上不会——共享边只离散一次,网格天然水密(见 3.4 节)。如果真的看到裂缝,通常是这两种情况:模型本身有自由边 / 缝隙(STEP 转换质量差,可用 ShapeFix_Shape 修复);或者裂缝出现在下游软件里——STL 不存拓扑,每个面的顶点各自存储,下游若不做顶点焊接会显示硬边/缝隙,这属于格式特性而非网格错误。
Q4:网格太密,怎么减少三角数?
按优先级:增大 Deflection → 增大 Angle → 设置更大的 DeflectionInterior / AngleInterior 让面内部稀疏 → 关闭 InternalVerticesMode。BRepMesh 本身不做网格简化(decimation),需要后处理可导出后用 MeshLab 等工具。
Q5:圆柱显示成明显的多边形,是网格化错了吗?
不是错误,是默认参数的视觉表现:Angle = 0.5 rad 意味着整圆最少约 13 段。把 Angle 调到 0.1~0.25 即可。另外注意 OCCT 的显示网格与导出网格是同一份数据,在交互查看器里看到的粗糙程度就反映了真实网格。
Q6:BRepMesh 的网格能直接用于有限元分析吗?
不能,定位不同:BRepMesh 做的是表面三角化(2D mesh),目标是几何逼近精度;FEA 需要的是体网格(四面体/六面体),且对单元长宽比、雅可比等有质量要求。OCCT 官方提供了 Netgen 等第三方体网格器的集成接口,或使用专业前处理软件。
Q7:网格化很慢甚至卡住,怎么排查?
- 大装配体先开
InParallel = true; - 检查
Deflection是否误设成了过小的绝对值(三角数随 1/d² 爆炸); - 某些 STEP 模型的面带有病态参数域(极端狭长的 UV 域),三角化会异常缓慢,可用
ShapeFix_Shape/ShapeUpgrade_UnifySameDomain预处理; MinSize保持默认即可,手动改小同样会引发三角数爆炸。
Q8:除了 STL,能导出 OBJ 或 glTF 吗?
可以,OCCT 提供 RWObj(OBJ)和 RWGltf(glTF 2.0)模块。注意 glTF/OBJ 的读写基于 XCAF 文档(带颜色、名称、实例结构):用 STEPCAFControl_Reader 把 STEP 读进 TDocStd_Document,再交给 RWGltf_CafWriter 导出,网格化同样在导出前用 BRepMesh_IncrementalMesh 完成。
八、进阶:访问网格数据(Poly_Triangulation)
网格化后,每个面的三角形数据挂在 Poly_Triangulation 上,通过 BRep_Tool::Triangulation 取出。下面的代码把全部三角形收集到全局坐标系:
1 |
|
三个容易踩的坑:
- 索引从 1 开始:
Node(i)、Triangle(i)都是 1-based(OCCT 传统),三角形返回的节点编号也是 1-based; - REVERSED 面的绕向:共享同一几何面的两个拓扑面朝向可能相反,不翻转会导致一半三角形法线朝内;
- Location 变换:复合形状(装配体)中,几何存在实例自身的局部坐标系里,必须应用
TopLoc_Location才能得到全局坐标。装配体里大量面共享同一份网格数据,只做一次变换即可获得正确结果,这也是 OCCT 实例化省内存的原因。
如果需要参数域坐标(如纹理贴图),可用 mesh->UVNode(i) 取出每个节点对应的
总结
OCCT 对 STEP 模型的网格化可以概括为一句话:BRepMesh_IncrementalMesh 先在 Deflection(弦高误差)和 Angle(角度误差)双重约束下离散所有边,再在面的 UV 参数域做以边离散点为约束的 Delaunay 三角化,并把结果缓存在拓扑结构上。工程上记住四件事就够了:
- 核心参数是
Deflection和Angle,经验起点是包围盒对角线 × 0.001 与 0.5 rad; - 导出 STL/OBJ/glTF 前必须显式网格化;
- 换参数重新网格化前先
BRepTools::Clean; - 共享边只离散一次,所以网格天然水密,可直接用于 3D 打印。
参考资料
- OCCT 官方用户指南:Mesh
- BRepMesh_IncrementalMesh 类参考
- IMeshTools_Parameters 类参考
- OCCT 源码:
src/BRepMesh/(面三角化)、src/GCPnts/(曲线离散)
- Title: OCCT 中 STEP 模型网格化算法详解:BRepMesh 原理、参数与实践
- Author: Ryan Lu
- Created at : 2026-07-17 00:00:00
- Updated at : 2026-07-17 14:44:10
- Link: http://ryan-hub.site/7b5ec9c29354/
- License: This work is licensed under CC BY-NC-SA 4.0.