【OCCT+ImGUI系列】010-BRepMesh-网格化IncrementalMesh
在三维模型处理中,网格化(Meshing)是将几何模型离散为三角面片的关键步骤。本文基于 OpenCascade 的 BRepMesh_IncrementalMesh
类,结合交互式演示系统,详解网格化参数调节、实时更新与可视化。
一、BRepMesh_IncrementalMesh 核心机制
BRepMesh_IncrementalMesh
是 OpenCascade 的增量式网格生成器,采用动态精度控制算法,支持以下关键参数:
- LinearDeflection:线性偏差(模型空间单位)
- AngularDeflection:角度偏差(弧度制)
- InParallel:启用多线程加速
通过构造球体示例演示核心调用方式:
TopoDS_Shape shape = BRepPrimAPI_MakeSphere(50.0).Shape();
IMeshTools_Parameters params;
params.Deflection = 1.0;
params.Angle = 30 * M_PI / 180;BRepMesh_IncrementalMesh mesher;
mesher.SetShape(shape);
mesher.ChangeParameters() = params;
mesher.Perform(); // 执行网格化
二、交互式教学系统功能
1. 动态参数调节与实时更新
通过 ImGui 滑动条实现参数动态调节,修改后触发网格重建:
// 线性偏差调节(0.1~0.7)
if (ImGui::SliderFloat("Linear Deflection", &linearDeflection, 0.1f, 0.7f)) {bMeshDirty = true; // 设置网格更新标志
}// 角度偏差调节(5°~30°)
float angularDeg = angularDeflection * 180 / M_PI;
if (ImGui::SliderFloat("Angular Deflection", &angularDeg, 5.0f, 30.0f)) {angularDeflection = angularDeg * M_PI / 180;bMeshDirty = true;
}
参数修改后通过
bMeshDirty
标志触发updateMesh
函数,保证视图实时响应
2. 网格清除与重置
通过BRepTools::Clean
清除模型三角化数据,配合上下文更新实现网格重置:
void clearTriangulation(const TopoDS_Shape& shape) {for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {BRepTools::Clean(TopoDS::Face(exp.Current()));}
}
3. 三角化信息统计
遍历所有面的三角化数据,统计总三角形数量:
int totalTriangles = 0;
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {Handle(Poly_Triangulation) tri = ...;if (!tri.IsNull()) totalTriangles += tri->NbTriangles();
}
ImGui::Text("Total Triangles: %d", totalTriangles);
4. 网格线框可视化
提取每个三角面片的边线,生成红色线框辅助显示:
void drawTriangulations(...) {for (each triangle in triangulation) {gp_Pnt p1 = tri->Node(n1).Transformed(...);// 创建三角形边线BRepBuilderAPI_MakePolygon poly;poly.Add(p1); poly.Add(p2); poly.Add(p3); poly.Close();Handle(AIS_Shape) aisTri = new AIS_Shape(poly.Shape());aisTri->SetColor(Quantity_NOC_RED);context->Display(aisTri, false);}
}
三、高级技巧与注意事项
-
多线程加速
启用InParallel
参数可提升复杂模型处理速度:meshParams.InParallel = true; // 开启并行计算
-
网格生成验证
检查IsDone()
状态确保网格生成成功:if (!mesher.IsDone()) {std::cerr << "Mesh generation failed!" << std::endl; }
-
显示模式控制
强制设置AIS_Shape显示模式,增强可视化效果:aisShape->SetDisplayMode(AIS_Shaded); // 实体着色模式 aisShape->Attributes()->SetFaceBoundaryDraw(true); // 显示面边界
四、代码
#pragma once#include "pch.h"
#include <format>
#include <string>
#include <mutex>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepPrimAPI_MakeSphere.hxx> // 新增头文件
#include <BRepLib_ToolTriangulatedShape.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <TopExp_Explorer.hxx>
#include <Poly_Triangulation.hxx>
#include <AIS_Shape.hxx>
#include <TopoDS.hxx>
#include "BaseScene.h"
#include "VisSceneComponents.h"
#include "TutorialWindow.h"
#include "CodeHintAction.h"class BRepMesh010 : public BaseScene, public VisSceneComponents, public TutorialWindow {
public:BRepMesh010() {openTutorialWindow();}void displayScene(const Handle(V3d_View)& view, const Handle(AIS_InteractiveContext)& context) override {if (!bIsSceneInit) {sceneInit(view, context);bIsSceneInit = true;}if (bMeshDirty) {updateMesh(context);bMeshDirty = false; }renderTutorialWindow(context);}void customInitTutorialWindow(const Handle(AIS_InteractiveContext)&) override {}private:Handle(AIS_Shape) aisShape;CodeHintManager hintMgr; TopoDS_Shape meshShape;IMeshTools_Parameters meshParams;std::mutex meshMutex;float linearDeflection = 1.0f;float angularDeflectionDeg = 30.0f;float minSize = 0.0f;bool isProcessing = false; // 标记是否正在处理bool bMeshDirty = false; // 参数变化刷新标志位void sceneInit(const Handle(V3d_View)&, const Handle(AIS_InteractiveContext)& context) override {meshShape = BRepPrimAPI_MakeSphere(50.0).Shape();updateMesh(context);}void updateMesh(const Handle(AIS_InteractiveContext)& context) {std::lock_guard<std::mutex> lock(meshMutex); // 自动加锁// 开始处理isProcessing = true;clearTriangulation(meshShape);meshParams.Deflection = linearDeflection;meshParams.Angle = angularDeflectionDeg * M_PI / 180.0;meshParams.InParallel = true;BRepMesh_IncrementalMesh mesher;mesher.SetShape(meshShape);mesher.ChangeParameters() = meshParams;mesher.Perform();hintMgr.AddHint("Mesh", "mesher.Perform();");// 添加网格生成验证if (!mesher.IsDone()) {std::cerr << "Mesh generation failed!" << std::endl;return;}aisShape = new AIS_Shape(meshShape);// 强制设置显示模式为网格//aisShape->SetDisplayMode(AIS_Shaded); // 或 AIS_WireFrameaisShape->Attributes()->SetFaceBoundaryDraw(true);context->RemoveAll(true);context->Display(aisShape, true);context->UpdateCurrentViewer(); // 强制刷新视图drawTriangulations(meshShape, context);}void clearTriangulation(const TopoDS_Shape& shape) {for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {TopoDS_Face face = TopoDS::Face(exp.Current());BRepTools::Clean(face); // 移除 Poly_Triangulation}}void renderTutorialContent(const Handle(AIS_InteractiveContext)& context) override {ImGui::Text("BRepMesh_IncrementalMesh 教学示例");ImGui::Separator();float oldLinearDeflection = linearDeflection;if (ImGui::SliderFloat("Linear Deflection", &linearDeflection, 0.1f, 0.7f, "%.2f")) {if (oldLinearDeflection != linearDeflection) {bMeshDirty = true;}}float oldAngularDeflectionDeg = angularDeflectionDeg;if (ImGui::SliderFloat("Angular Deflection (deg)", &angularDeflectionDeg, 5.0f, 11.0f, "%.1f")) {if (oldAngularDeflectionDeg != angularDeflectionDeg) {bMeshDirty = true;}}if (ImGui::Button("Clear Triangulation")) {BRepTools::Clean(meshShape);context->RemoveAll(true);hintMgr.AddHint("BRepTools::Clean", "BRepTools::Clean(meshShape);");}if (ImGui::Button("Reset Default")) {linearDeflection = 1.0f;angularDeflectionDeg = 30.0f;minSize = 0.0f;updateMesh(context);}if (aisShape) {ImGui::Separator();ImGui::Text("Triangulation Info:");int totalTriangles = 0;for (TopExp_Explorer exp(meshShape, TopAbs_FACE); exp.More(); exp.Next()) {TopLoc_Location loc;Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(TopoDS::Face(exp.Current()), loc);if (!tri.IsNull()) {totalTriangles += tri->NbTriangles();}}ImGui::Text("Total Triangles: %d", totalTriangles);}// 渲染提示窗口hintMgr.RenderWindow();}void drawTriangulations(const TopoDS_Shape& shape, const Handle(AIS_InteractiveContext)& context) {for (TopExp_Explorer faceExp(shape, TopAbs_FACE); faceExp.More(); faceExp.Next()) {TopoDS_Face face = TopoDS::Face(faceExp.Current());TopLoc_Location loc;Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);if (tri.IsNull()) continue;const Poly_Array1OfTriangle& triangles = tri->Triangles();for (int i = triangles.Lower(); i <= triangles.Upper(); ++i) {int n1, n2, n3;triangles(i).Get(n1, n2, n3);// 使用 tri->Node(index) 获取三角形顶点坐标gp_Pnt p1 = tri->Node(n1).Transformed(loc.Transformation());gp_Pnt p2 = tri->Node(n2).Transformed(loc.Transformation());gp_Pnt p3 = tri->Node(n3).Transformed(loc.Transformation());// 创建一个三角形边线展示BRepBuilderAPI_MakePolygon triPoly;triPoly.Add(p1);triPoly.Add(p2);triPoly.Add(p3);triPoly.Add(p1);triPoly.Close();Handle(AIS_Shape) aisTri = new AIS_Shape(triPoly.Shape());aisTri->SetDisplayMode(AIS_WireFrame);aisTri->SetColor(Quantity_NOC_RED);context->Display(aisTri, false);}}context->UpdateCurrentViewer();}};