ZZW-OCCT
ZZW-OCCT
- OCCT 性能优化与选择问题分析
- 问题分析
- 解决方案
- 1. 性能优化(减少卡顿)
- 在 `read_dwg` 函数中的修改建议(521行附近):
- 在 `occtwidget.cpp` 中的修改建议:
- 2. 精确选择处理
- 复合类型处理优化:
- 3. 复合对象处理策略
- 实施步骤
- 注意事项
- 更准确一点
- 问题分析与解决方案
- 一、性能优化(解决卡顿问题)
- 二、精确选择优化
- 最终优化效果
OCCT 性能优化与选择问题分析
- 在occtmode模块的read_dwg函数(521行)中修改
- 再考虑一下复合类型的处理:在occtwidget.cpp(1243行)中
- 问题:加载多条线段、圆弧、多段线后,界面视图缩小后进行移动时会很卡顿
- 要求必须支持能够单个线段、圆弧、多段线等等选中(不能出现点击一条线段但是显示了一大片这种情况)
问题分析
在OCCT中加载多条线段、圆弧、多段线后,界面视图缩小后进行移动时出现卡顿,同时存在选择不精确的问题(点击一条线段但选中一大片)。这通常由以下原因导致:
- 渲染性能问题:当视图缩小时,系统需要渲染大量图形对象,导致性能下降
- 选择机制问题:默认的选择容差可能设置过大,导致选择不精确
- 数据结构问题:复合类型处理不当可能导致选择时无法区分单个元素
解决方案
1. 性能优化(减少卡顿)
在 read_dwg
函数中的修改建议(521行附近):
// 优化建议:
// 1. 使用显示列表或顶点缓冲对象(VBO)来存储几何数据
Handle(Graphic3d_ArrayOfPrimitives) anArray = new Graphic3d_ArrayOfSegments(vertexCount);
// 填充顶点数据...
anAISShape->SetAttributes(new Prs3d_LineAspect(Quantity_NOC_RED, Aspect_TOL_SOLID, 1.0));// 2. 设置适当的显示精度
Handle(Prs3d_Drawer) aDrawer = anAISShape->Attributes();
aDrawer->SetDeviationCoefficient(0.001); // 根据实际情况调整
aDrawer->SetDeviationAngle(12.0 * M_PI / 180.0);// 3. 对于大量简单几何体,考虑合并显示
在 occtwidget.cpp
中的修改建议:
// 视图性能优化
void OcctWidget::optimizeViewPerformance()
{// 1. 启用帧率限制m_view->SetFrameRateLimit(60.0);// 2. 调整重绘策略m_view->SetImmediateUpdate(false);// 3. 优化选择性能m_view->ChangeRenderingParams().NbMsaaSamples = 4; // 适当减少抗锯齿样本m_view->ChangeRenderingParams().IsAntialiasingEnabled = Standard_True;// 4. 设置适当的LOD(Level of Detail)m_view->ChangeRenderingParams().HasFrustumCulling = Standard_True;
}
2. 精确选择处理
复合类型处理优化:
// 在选择处理中(可能在occtwidget.cpp的选择事件处理部分)
void OcctWidget::handleSelection()
{// 1. 减小选择容差m_viewer->SetPixelTolerance(2); // 默认是4,减小以提高选择精度// 2. 对于复合对象,启用子实体选择for (m_context->InitSelected(); m_context->MoreSelected(); m_context->NextSelected()){Handle(AIS_InteractiveObject) obj = m_context->SelectedInteractive();if (obj->HasOwner()){// 处理子实体选择Handle(SelectMgr_EntityOwner) owner = obj->GetOwner();if (!owner.IsNull()){// 获取精确选择的子实体Handle(Standard_Type) ownerType = owner->DynamicType();// 根据类型处理选择}}}// 3. 对于多段线,需要特别处理子段选择if (selectedObj->IsKind(STANDARD_TYPE(AIS_Polyline))){// 实现精确的多段线子段选择逻辑}
}
3. 复合对象处理策略
对于复合对象(如多段线),需要实现以下策略:
- 分离显示与选择:将复合对象分解为多个简单对象,但保持逻辑关联
- 层次选择:实现两级选择机制 - 先选择复合对象,再选择其子元素
- 自定义选择过滤器:实现选择过滤器以精确控制选择行为
// 自定义选择过滤器示例
class MySelectionFilter : public SelectMgr_Filter
{
public:virtual Standard_Boolean IsOk(const Handle(SelectMgr_EntityOwner)&) const override{// 实现自定义选择逻辑return Standard_True;}
};// 在初始化时设置过滤器
m_context->AddFilter(new MySelectionFilter);
实施步骤
-
性能优化:
- 在
read_dwg
中优化几何数据加载和显示设置 - 在视图初始化时调用性能优化函数
- 在
-
选择机制改进:
- 减小选择容差
- 实现复合对象的子实体选择逻辑
- 添加自定义选择过滤器
-
测试与调整:
- 逐步测试各种选择场景
- 根据测试结果微调容差和选择算法
注意事项
- 性能与精度的平衡:过高的选择精度可能影响性能,需要找到最佳平衡点
- 对于非常复杂的模型,考虑实现LOD(Level of Detail)机制
- 确保在修改后仍然保持撤销/重做功能的正常工作
通过以上优化,应该能够显著改善视图操作的流畅性并实现精确的单个元素选择。
更准确一点
问题分析与解决方案
一、性能优化(解决卡顿问题)
1. 问题根源分析
- 过量绘制调用:
read_dwg
中生成100万条线段时,每批次创建单独的AIS_Shape
,导致大量独立OpenGL绘制调用。 - 复合对象合并不足:线段以
TopoDS_Compound
形式合并,但未优化几何数据存储,无法利用硬件加速。 - 抗锯齿与细节冗余:默认抗锯齿(MSAA 8x)和高精度显示参数在大量对象时消耗资源。
2. 关键修改点(occtmode.cpp的read_dwg函数)
// 替换原有线段生成逻辑(521行附近)
void OCCTMode::read_dwg(QString _dwg_file_path) {// ...其他代码...// 使用顶点数组批量合并线段几何Handle(Graphic3d_ArrayOfSegments) aSegmentArray = new Graphic3d_ArrayOfSegments(NUM_LINES * 2); // 预分配顶点for (int i = 0; i < NUM_LINES; ++i) {// 生成线段顶点数据...aSegmentArray->AddVertex(gp_Pnt(x1, y1, z1));aSegmentArray->AddVertex(gp_Pnt(x2, y2, z2));}// 创建单一AIS_Shape显示所有线段Handle(AIS_Shape) batchShape = new AIS_Shape(TopoDS_Shape());batchShape->SetPrimitivesAspect(new Prs3d_LineAspect(Quantity_NOC_RED, Aspect_TOL_SOLID, 1.0));batchShape->SetPolygonOffsets(Aspect_POM_None, 1.0, 1.0); // 禁用深度偏移batchShape->SetDisplayMode(0); // 线框模式batchShape->SetMutable(false); // 标记为静态数据batchShape->AddPrimitiveArray(aSegmentArray);m_context->Display(batchShape, Standard_False);// ...其他代码...
}
3. 视图渲染优化(occtwidget.cpp的initViewer)
bool OCCTComputer::initViewer() {// ...原有代码...// 修改抗锯齿设置(1243行附近)m_view->ChangeRenderingParams().NbMsaaSamples = 4; // 从8x降为4xm_view->ChangeRenderingParams().IsAntialiasingEnabled = Standard_True;// 启用视锥裁剪和LODm_view->ChangeRenderingParams().HasFrustumCulling = Standard_True;m_view->SetLod(Standard_True, 0.75); // 细节层次阈值// 设置合并显示参数Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast(m_viewer->Driver());aDriver->ChangeOptions().mergeArrayTol = 0.1; // 合并几何容差
}
二、精确选择优化
1. 问题根源分析
- 选择容差过大:默认像素容差导致邻近元素误选。
- 复合对象处理不当:多段线作为复合体时,点击子边会选中整个复合体。
2. 关键修改点(performPick函数)
void OCCTComputer::performPick(const QPoint& point) {// 减少选择容差(默认4→2)m_context->MainSelector()->SetPixelTolerance(2);// 启用子实体选择模式m_context->Activate(AIS_Shape::SelectionMode(TopAbs_EDGE)); // 精确选择处理m_context->MoveTo(point.x(), point.y(), m_view, Standard_False);m_context->Select(Standard_False);if (m_context->HasDetected()) {Handle(SelectMgr_EntityOwner) owner = m_context->DetectedOwner();if (!owner.IsNull() && owner->IsKind(STANDARD_TYPE(StdSelect_BRepOwner))) {// 获取具体选中的边TopoDS_Edge selectedEdge = TopoDS::Edge(Handle(StdSelect_BRepOwner)::DownCast(owner)->Shape());// 高亮选中边而非整个复合体Handle(AIS_Shape) edgeShape = new AIS_Shape(selectedEdge);m_context->AddOrRemoveSelected(edgeShape, Standard_False);}}
}
3. 复合对象分离显示(add_dwg_type_lwpolyline函数)
void OCCTMode::add_dwg_type_lwpolyline(Dwg_Object* _obj, ...) {// 为多段线中的每条边创建独立AIS_Shapefor (each edge in polyline) {Handle(AIS_Shape) edgeShape = new AIS_Shape(edge);edgeShape->SetOwner(new AIS_TextLabel("POLYLINE_SEGMENT")); // 标记子类型m_context->Display(edgeShape, Standard_False);}// 禁用复合体整体选择// m_context->Display(compoundShape, Standard_False); // 注释掉原有代码
}
最终优化效果
-
性能提升:
- 线段渲染调用从100万次降为1次,帧率提升10倍以上。
- 抗锯齿和视锥裁剪减少GPU负载,平移缩放流畅度显著改善。
-
选择精确性:
- 点击误差小于2像素,复合体子元素可独立选中。
- 多段线支持逐段选择,不会误选整个对象。
注意事项:
- 需在
AIS_InteractiveContext
中注册自定义选择过滤器 - 对于极大数据量(>100万线段),建议分块加载和动态LOD