Open CASCADE 用户指南:可视化

文章目录

这篇文章来源于 dev.opencascade.org,使用 Microsoft Edge 翻译,原文 Open CASCADE Technology - User Guides: Visualization

OCCT 用户指南按 OCCT 模块组织:

  • 基础类
  • 建模数据
  • 建模算法
  • 网格
  • 形状修复
  • 可视化
  • VTK 集成服务(VIS)
  • IGES 转换器
  • STEP 转换器
  • 扩展数据交换(XDE)
  • Open CASCADE 应用程序框架(OCAF)
  • Draw 测试工具
  • 检查器

介绍

Open CASCADE Technology 中的可视化基于以下各项的分离:

  • 一方面 – 存储要显示和选择的实体的几何和拓扑的数据,以及
  • 另一方面 – 它的呈现(presentation)(当一个对象在场景中显示时你所看到的)和选择(selection)(可以交互方式选择整个对象或其子部分,以将应用程序定义的操作应用于所选实体)。

呈现功能通过 Presentation 组件进行管理,选择功能通过 Selection 组件进行管理。

应用程序交互服务(AIS - Application Interactive Services) 提供了在应用程序 GUI 视图和包之间创建链接的方法,这些链接用于管理 selectionpresentation,这使得 3D 中这些功能的管理更加直观,因此更加透明。

AIS 使用 交互对象(Interactive Object) 的概念,这是一个可显示且可选择的实体,它表示应用程序数据中的元素。因此,在 3D 中,您(用户)无需熟悉 AIS 底层的任何功能,除非您想创建自己的交互对象或选择过滤器。

但是,如果您需要所提供之外的交互对象和过滤器类型,则需要了解可呈现和可选择对象的机制,特别是如何实现它们的虚函数。要做到这一点,需要熟悉 敏感基元(Sensitive Primitive)和 可呈现对象(Presentable Object)等基本概念。

以下包(package)用于显示 3D 对象:

用于显示 3D 对象的包也适用于 2D 对象的可视化。

下图显示了可视化中关键概念和包之间关系的示意图。当然,“几何和拓扑 (Geometry & Topology)”只是可以由 AIS 处理的应用程序数据的一个例子,特定于应用程序的交互对象可以处理任何类型的数据。

在这里插入图片描述

可视化中的关键概念和包

为了满足 CASCADE 用户的不同需求,本用户指南提供了以下三种阅读途径。

基本概念

呈现(Presentation)

在 Open CASCADE Technology 中,呈现(presentation)服务与它们所表示的数据分离,这些数据由应用算法生成。此划分允许您在不修改可视化服务的情况下修改几何或拓扑算法及其生成的对象。

Presentation 的结构

在屏幕上显示一个对象涉及三种实体:

可呈现对象

可呈现对象的目的是以 Graphic3d_Structure 的形式提供对象的图形表示。在第一次显示请求时,它通过调用适当的算法来创建此结构,并保留此框架以供进一步显示。

StdPrsPrs3d 包中提供了标准呈现算法。但是,您可以编写自己的特定呈现算法,前提是它们创建由 Graphic3d 包中的结构组成的呈现。您还可以为单个可呈现对象创建多个呈现(presentation):每个呈现都可用于你的应用程序支持的每种可视化模式。

每个要单独呈现的对象都必须是可呈现的或与可呈现的对象相关联。

查看器(viewer)

查看器允许以交互方式操作对象的视图(view)。缩放、平移或旋转视图时,查看器将对可呈现对象创建的图形结构进行操作,而不是对应用程序的数据模型进行操作。通过在呈现算法中创建 Graphic3d 结构,您可以使用 Open CASCADE Technology 中提供的 3D 查看器进行 3D 可视化。

交互上下文

交互上下文通过通用的高级 API 控制整个呈现过程。当应用程序请求显示对象时,交互上下文会向可呈现对象请求图形结构,并将其发送给查看器进行显示。

Presentation 包(package)

Presentation 至少涉及 AISPrsMgrStdPrsV3d 包。如果您需要实现自己的呈现算法,则可以使用其他包,例如 Prs3dGraphic3d

  • 标准交互对象

    • AIS 包提供了用于实现交互对象(可呈现和可选择的实体)的类。
    • PrsDim 包为绘图尺寸和关系提供可呈现的对象。
    • MeshVS 包为处理网格数据提供了可呈现的对象 MeshVS_Mesh
  • 标准呈现构建器

    • Prs3d 包为箭头、圆柱体、球体等简单几何形状提供现成的标准呈现算法。它还定义 Prs3d_Drawer 类,用于控制要创建的 presentation 在颜色、线条类型、粗细等方面的属性。
    • StdPrs 包为 B-Rep 形状提供现成的标准呈现算法。它提供了通用的呈现算法,例如着色、线框、等值线和隐线消除。
    • DsgPrs 包提供了用于显示尺寸、关系和 XYZ 三面体的工具。
  • 选择服务

  • 查看器管理
    V3d 包提供 3D 查看器支持的服务。

  • 低级接口

基本示例:如何显示 3D 对象

Handle(V3d_Viewer) theViewer;
Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext(theViewer);
BRepPrimAPI_MakeWedge aWedgeMaker(theWedgeDX, theWedgeDY, theWedgeDZ, theWedgeLtx);
TopoDS_Solid aShape = aWedgeMaker.Solid();
Handle(AIS_Shape) aShapePrs = new AIS_Shape(aShape); // creation of the presentable object
aContext->Display(aShapePrs, AIS_Shaded, 0, true);   // display the presentable object and redraw 3d viewer

形状是使用 BRepPrimAPI_MakeWedge 命令创建的。然后从形状创建 AIS_Shape。调用 Display 命令时,交互上下文调用可呈现对象的 Compute 方法来计算呈现数据并将其传输给查看器。见下图。

在这里插入图片描述

显示可呈现形状所涉及的过程

选择(Selection)

标准的 OCCT 选择算法由动态和静态两部分表示。动态(Dynamic)选择会使对象当鼠标光标移动到对象上时自动突出显示。静态(Static)选择允许拾取(pick)特定对象(或多个对象)进行进一步处理。

有 3 种不同的选择类型:

  • Point selection 点选 – 允许拾取和突出显示位于鼠标光标下方的单个对象(或其部分);
  • Rectangle selection 框选 – 允许拾取位于由鼠标开始和结束光标位置定义的矩形下方的对象或其部分;
  • Polyline selection 多边形选择 – 允许拾取位于用户定义的非自相交折线下的对象或其部分。

对于 OCCT 选择算法,所有可选择对象都表示为一组敏感区域,称为 敏感实体(sensitive entities)。当鼠标光标在视图中移动时,将分析每个对象的敏感实体是否发生碰撞。

术语和概念

本节介绍整个算法描述中使用的基本术语和概念。

敏感实体(Sensitive entity)

敏感实体与实体所有者一样,是对象和选择机制之间的链接。

实体的用途是定义对象的哪些部分是可选择的。因此,任何可选择的对象都必须拆分为敏感实体(一个或多个)。例如,要对对象应用面选择,必须将其分解为面,并使用它们来创建敏感实体集。

在这里插入图片描述

将形状划分为敏感实体的示例

根据用户的需要,敏感实体可以是原子的(点或边缘)或复合的。复合实体包含许多子元素,检测机制可以以类似的方式处理这些子元素(例如,存储为一组线段或三角剖分的折线)。

实体用作选择算法的内部单元,不包含任何拓扑数据,因此它们具有指向维护拓扑特定方法的上层接口的链接。

实体所有者

每个 Select3D_SensitiveEntity 都存储对其所有者 SelectMgr_EntityOwner 的引用,该所有者是连接实体和相应可选择对象(SelectMgr_SelectableObject)的类。此外,所有者可以存储任何附加信息,例如,敏感实体的拓扑形状、突出显示颜色和方法,或者实体是否被选中。

选择(Selection)

为了简化对象的不同选择模式的处理,链接到其所有者的敏感实体被组织成集合,称为 selectionsSelectMgr_Selection)。每个选择(selection)都包含为特定模式创建的实体以及敏感性和更新状态。

可选择对象

可选择对象(SelectMgr_SelectableObject 或更准确地说是 AIS_InteractiveObject)存储有关所有创建的选择模式和敏感实体的信息。

可选择对象的所有继承对象都必须实现根据给定模式将其呈现(presentation)拆分为敏感实体的方法。计算出的实体排列在一个选择(selection)中,并添加到此对象的所有选择列表中。在永久删除对象之前,不会从列表中删除任何选择(selection)。

对于所有标准 OCCT 交互对象,零模式应该选择整个对象(但可以在自定义对象中重新定义)。例如,AIS_Shape 对象确定以下模式(参见 AIS_Shape::SelectionMode()):

在这里插入图片描述

从敏感实体到可选择对象的引用层次结构

在这里插入图片描述

可选择对象内的实体组织原则

查看器选择器(Viewer selector)

对于每个 OCCT 查看器,都有一个查看器选择器类 SelectMgr_ViewerSelector3d。它为整个选择算法提供了一个高级 API,并封装了对每个鼠标拾取的敏感实体和对象的处理。查看器选择器维护选择模式的激活和停用,启动算法,该算法检测要拾取的候选实体,并存储其结果,并实现用于使选择结构保持最新的接口。

选择管理器(Selection manager)

选择管理器 SelectMgr_SelectionManager 是一个高级 API,用于操作所有显示对象的选择。它处理所有查看器选择器,激活和停用所有或特定选择器中对象的选择模式,管理每个对象选择(selection)的计算和更新。此外,它还会根据应用的变化保持选择结构的更新。

在这里插入图片描述

查看器选择器和选择管理器之间的关系链

算法

所有三种类型的 OCCT 选择都作为一个概念实现,基于通过 3 级 BVH 树遍历搜索视锥体和敏感实体之间的重叠。

选择视锥体

每次运行选择算法的第一步是根据当前激活的选择类型构建选择视锥体。

对于点选或框选,视锥体的底面是一个矩形,分别符合像素公差或用户定义区域的尺寸。对于多边形选择,由构造线定义的多边形被三角化,每个三角形都用作其自身视锥体的底。因此,这种类型的选择使用一组三角形视锥体进行重叠检测。

视锥体长度受视锥体近裁面和远裁面的限制,每个平面都平行于相应的视锥体平面构建。

在这里插入图片描述

上图显示了矩形视锥体:a) 鼠标移动或单击后,b) 应用矩形选择后。

在这里插入图片描述

在上图中,设置了三角形视锥体:a) 用户定义的折线,b) 基于给定折线的多边形三角化,c) 基于其中一个三角形的三角形视锥体。

BVH 树

为了在查看器级别保持选择机制,使用了由 3 个 BVH 树组成的加速结构。

第一级树由每个可选择对象的轴对齐边界框构成。因此,该树的根包含所有可选择边界的组合,即使它们当前没有激活的选择。对象在显示 AIS_InteractiveObject 期间添加,并且仅在对象被销毁时才会从该树中删除。第一级 BVH 树是在首次运行选择算法的同时按需构建的。

第二级 BVH 树由一个可选择对象的所有敏感实体组成。当默认模式被激活时,第二级树会自动构建,并在首次计算新选择模式时重新构建。

第三级 BVH 树用于包含许多元素的复合敏感实体:例如,三角化、具有许多段的线、点集等。它是针对具有超过 800K 子元素(由 StdSelect_BRepSelectionTool::PreBuildBVH() 定义)的敏感实体的需求构建的。

在这里插入图片描述

选择 BVH 树层次结构:从最大的对象级别(第一个)到最小的复合实体级别(第三个)

算法的阶段

该算法包括预处理和三个主要阶段。

预处理

意味着计算选择视锥体及其主要特征。

第一阶段 – 遍历第一级 BVH 树

成功构建选择视锥体后,算法开始遍历对象级 BVH 树。根据 分离轴定理(SAT) 的条款,测试包含轴对齐边界框的节点是否与选择视锥体重叠。当遍历向下到叶节点时,这意味着已找到具有可能重叠敏感实体的候选对象。如果没有检测到这样的对象,则算法将停止,并假定不需要选择任何对象。否则,它将进入下一阶段,以处理找到的可选择对象的实体。

第二阶段 – 遍历第二级 BVH 树

在这个阶段,有必要确定一个对象的所有敏感实体中是否存在候选对象。

首先,在这个阶段,算法会检查是否对当前对象应用了任何转换。如果它有自己的位置,那么相应转换的视锥体将用于进一步的计算。在下一步中,访问给定对象的第二级 BVH 树的节点以搜索重叠的叶子。如果没有找到这样的叶子,则算法将返回到第二阶段。否则,它将通过执行以下检查开始处理找到的实体:

  • 激活检查 - 该实体目前可能处于非活动状态,因为它属于已停用的选择;
  • 公差检查 - 当前选择视锥体可能太大而无法进一步检查,因为它始终在所有激活的实体中以最大公差构建;因此,在这一步骤中,视锥体可能会被缩放。

完成这些检查后,算法将进入最后阶段。

第三阶段 – 特定敏感实体的重叠或包含测试

如果实体是原子的,则执行简单的 SAT 测试。对于复合实体,将遍历第三级 BVH 树。分析匹配敏感实体的定量特征(如深度、到几何中心的距离),并应用剪裁平面(如果已设置)。检测结果被存储,算法返回第二阶段。

包和类(Packages and classes)

选择(Selection)是作为各种算法的组合实现的,这些算法被划分为几个包 — SelectBasicsSelect3DSelectMgrStdSelect

SelectBasics

SelectBasics 包包含可供选择的基本类和接口。最值得注意的是:

每个自定义敏感实体必须至少继承 SelectBasics_SensitiveEntity

Select3D

Select3D 包提供了标准敏感实体的定义,例如:

  • box;
  • circle;
  • curve;
  • face;
  • group;
  • point;
  • segment;
  • triangle;
  • triangulation;
  • wire.

每个基本的敏感实体都继承 Select3D_SensitiveEntity。该软件包还包含两个辅助类,Select3D_SensitivePolySelect3D_SensitiveSet

Select3D_SensitiveEntity – 敏感实体的基本定义。

Select3D_SensitiveSet – 需要使用第三级 BVH 的所有复合敏感实体的基类。它实现树的遍历,并为检查子实体的方法定义接口。

Select3D_SensitivePoly – 描述任意点集并实现选择的基本函数。重要的是要知道,这个类不执行任何内部数据检查。因此,从 Select3D_SensitivePoly 继承的敏感实体的自定义实现必须满足分离轴定理(Separating Axis Theorem)的条款,才能使用标准的 OCCT 重叠检测方法。

SelectMgr

SelectMgr 包用于维护整个选择过程。为此,该软件包提供以下服务:

  • 激活和停用所有可选择对象的选择模式;
  • 用于计算对象选择模式的接口;
  • 选择过滤器类的定义;
  • 使选择的 BVH 数据保持最新。

主要类的简要说明:

StdSelect

StdSelect package 包含一些 SelectMgr 类的实现和用于创建选择结构的工具。例如

使用示例

第一个代码片段演示了自定义交互式对象中 SelectMgr_SelectableObject::ComputeSelection() 方法的实现。该方法用于计算用户定义的选择模式。让我们假设需要使一个盒子在两种模式下可供选择 —— 整个形状(模式 0)和它的每个边(模式 1)。若要选择整个盒子,应用程序可以为交互式对象的每个面创建一个敏感基元。在这种情况下,所有基元共享同一个所有者 —— 盒子本身。若要选择盒子边缘,应用程序必须为每条边创建一个敏感基元。在这里,所有敏感实体都不能共享所有者,因为选择过程的结果,必须突出显示不同的几何基元。

void InteractiveBox::ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
                                       const Standard_Integer theMode)
{
  switch (theMode)
  {
    case 0:   // creation of face sensitives for selection of the whole box
    {
      Handle(SelectMgr_EntityOwner) anOwner = new SelectMgr_EntityOwner(this, 5);
      for (Standard_Integer aFaceIter = 1; aFaceIter <= myNbFaces; ++aFaceIter)
      {
        Select3D_TypeOfSensitivity aSensType = myIsInterior;
        theSel->Add (new Select3D_SensitiveFace (anOwner, myFaces[aFaceIter]->PointArray(), aSensType));
      }
      break;
    }
    case 1: // creation of edge sensitives for selection of box edges only
    {
      for (Standard_Integer anEdgeIter = 1; anEdgeIter <= 12; ++anEdgeIter)
      {
        // 1 owner per edge, where 6 is a priority of the sensitive
        Handle(MySelection_EdgeOwner) anOwner = new MySelection_EdgeOwner(this, anEdgeIter, 6);
        theSel->Add (new Select3D_SensitiveSegment (anOwner, myFirstPnt[anEdgeIter]), myLastPnt[anEdgeIter]));
      }
      break;
    }
  }
}

用于创建选择结构的算法将敏感基元存储在 SelectMgr_Selection 实例中。对象选择列表中的每个 SelectMgr_Selection 序列都必须对应于特定的选择模式。为了描述将对象分解为可选的基元,在 Select3D 包中提供了一组现成的敏感实体。自定义敏感基元可以通过从 Select3D_SensitiveEntity 继承来定义。要使自定义交互对象可选择或自定义现有对象的选择模式,必须定义实体所有者。它们必须继承 SelectMgr_EntityOwner 接口。

任何交互对象的选择结构都是在 SelectMgr_SelectableObject::ComputeSelection() 方法中创建的。下面的示例显示了如何使用在 StdSelect_BRepSelectionTool 中实现的标准 OCCT 机制来完成拓扑形状的不同选择模式的计算。

void MyInteractiveObject::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
                                            const Standard_Integer theMode)
{
  switch (theMode)
  {
    case 0: StdSelect_BRepSelectionTool::Load (theSelection, this, myShape, TopAbs_SHAPE);  break;
    case 1: StdSelect_BRepSelectionTool::Load (theSelection, this, myShape, TopAbs_VERTEX); break;
    case 2: StdSelect_BRepSelectionTool::Load (theSelection, this, myShape, TopAbs_EDGE);   break;
    case 3: StdSelect_BRepSelectionTool::Load (theSelection, this, myShape, TopAbs_WIRE);   break;
    case 4: StdSelect_BRepSelectionTool::Load (theSelection, this, myShape, TopAbs_FACE);   break;
  }
}

StdSelect_BRepSelectionTool 类提供了一个高级 API,用于使用来自给定 TopoDS_Shape 的拓扑数据计算给定类型的敏感实体(例如,面、顶点、边、线等)。

Open CASCADE Technology 采用的突出显示选定实体所有者的传统方式假定每个实体所有者都单独突出显示自己。这种方法有两个缺点:

  • 每个实体所有者都必须维护自己的 Graphic3d_Structure 对象,这会导致相当大的内存开销;
  • 从可视化的角度来看,逐个绘制选定的所有者效率不高。

因此,为了克服这些限制,OCCT 有一种替代方法来实现所选呈现(presentation)的突出显示。使用这种方法,交互对象本身将负责突出显示,而不是实体所有者。

SelectMgr_EntityOwner::IsAutoHilight() 返回值的基础上,AIS_InteractiveContext 对象要么使用传统的突出显示方式(如果 IsAutoHilight() 返回 TRUE),要么根据它们的可选择对象对这些所有者进行分组,最后调用 SelectMgr_SelectableObject::HilightSelected()SelectMgr_SelectableObject::ClearSelected(),将一组所有者作为参数传递。

因此,应用程序可以派生自己的交互对象,并从 SelectMgr_SelectableObject 重新定义虚方法 HilightSelected()ClearSelected()HilightOwnerWithColor()SelectMgr_SelectableObject::GetHilightPresentationSelectMgr_SelectableObject::GetSelectPresentation 方法可用于根据用户的需要优化所选内容的填充和突出显示。

在重新定义的 SelectMgr_SelectableObject::ComputeSelection() 方法中,在计算所有必要的敏感实体及相应的所有者,并将其打包到 SelectMgr_Selection 实例后,有必要通过以下步骤在 SelectMgr_SelectionManager 中注册准备好的选择:

  • 如果没有打开 AIS_InteractiveContext,则创建一个交互上下文并在其中显示可选择的对象;
  • 使用 AIS_InteractiveContext::Load() 方法将可选择对象加载到交互上下文的选择管理器中。如果作为参数传递给此方法的选择模式不等于 -1,则此选择模式的 ComputeSelection() 将被调用;
  • 使用 AIS_InteractiveContext::Activate()AIS_InteractiveContext::Deactivate() 方法激活或停用定义的选择模式。

完成这些步骤后,创建的交互上下文的选择管理器将包含给定的对象及其选择实体,并且它们将参与检测过程。

下面的代码片段演示了上述步骤。它还包含用于启动检测过程和解析选择结果的代码。

// Suppose there is an instance of class InteractiveBox from the previous sample.
// It contains an implementation of method InteractiveBox::ComputeSelection() for selection
// modes 0 (whole box must be selected) and 1 (edge of the box must be selectable)
Handle(InteractiveBox) theBox;
Handle(AIS_InteractiveContext) theContext;
// To prevent automatic activation of the default selection mode
theContext->SetAutoActivateSelection(false);
theContext->Display(theBox, false);
// Load a box to the selection manager without computation of any selection mode
theContext->Load(theBox, -1, true);
// Activate edge selection
theContext->Activate(theBox, 1);
// Run the detection mechanism for activated entities in the current mouse coordinates and in the current view.
// Detected owners will be highlighted with context highlight color
theContext->MoveTo(aXMousePos, aYMousePos, myView, false);
// Select the detected owners
theContext->Select();
// Iterate through the selected owners
for (theContext->InitSelected(); theContext->MoreSelected() && !aHasSelected; theContext->NextSelected())
{
  Handle(AIS_InteractiveObject) anIO = theContext->SelectedInteractive();
}
// deactivate all selection modes for aBox1
theContext->Deactivate(aBox1);

同样重要的是要知道,在 OCCT 中为矩形选择实现了 2 种类型的检测:

  • 包含(inclusive) 检测。在这种情况下,只有当敏感图元的所有点都包含在选择矩形定义的区域中时,才认为敏感图元被检测到;
  • 重叠(overlap) 检测。在这种情况下,当敏感图元与选择矩形部分重叠时,就认为检测到敏感图元。

标准 OCCT 选择机制默认使用包含检测。若要更改此设置,请使用以下代码:

// Assume there is a created interactive context
const Handle(AIS_InteractiveContext) theContext;
// Retrieve the current viewer selector
const Handle(StdSelect_ViewerSelector3d)& aMainSelector = theContext->MainSelector();
// Set the flag to allow overlap detection
aMainSelector->AllowOverlapDetection (true);

应用交互服务(AIS)

介绍

应用交互服务(Application Interactive Services)允许以简单透明的方式在查看器中管理呈现(presentations)和动态选择。用于管理可视化和选择的中心实体是交互上下文AIS_InteractiveContext)。它连接到主查看器 (V3d_Viewer)。

默认情况下,交互上下文从 “中性点”(Neutral Point) 开始,将每个可选择对象作为一个整体进行选取,但用户可以为特定对象激活 “局部选择”(Local Selection),以使成为对象的可选择的部分。局部/全局选择由为每个显示对象激活的选择模式列表管理,其中 0(默认选择模式)通常表示全局(整个对象)选择。

交互对象AIS_InteractiveObject) 是可视化和选择的实体。您可以使用已经编写了所有必要函数的标准交互对象类,也可以通过遵守下面所述的一定数量的规则和约定来实现你自己的交互对象类。

交互对象是一个“虚拟”实体,可以展示和选择。交互对象可以具有一定数量的特定图形属性,例如可视化模式、颜色和材质。可视化交互对象时,如果交互对象具有所需的自定义属性,则所需的图形属性从其自己的绘图器(Drawer)Prs3d_Drawer) 中获取,或者从上下文绘图器中获取。

在这里插入图片描述

可能需要筛选要选择的实体。因此,存在 Filter 实体(SelectMgr_Filter),它们允许优化动态检测上下文。其中一些过滤器只能在“中性点”内使用,而其他过滤器只能在“局部选择”内使用。可以编写自定义过滤器并将它们加载到交互上下文中。

交互对象

在 AIS 查看器中可视化和选择的实体是对象 (AIS_InteractiveObject)。它们将模型的基础参考几何图形连接到其在 AIS 中的图形表示。您可以使用标准交互对象的预定义 OCCT 类,这些类已为其编程了所有必要的功能,或者,如果您是高级用户,则可以实现自己的交互式对象类。

呈现(Presentations)

一个交互对象可以有任意数量的呈现(Presentations),只要其创建者想要提供。3D 呈现(Presentations)由 Presentation ManagerPrsMgr_PresentationManager) 管理。由于这在 AIS 中是透明的,因此用户不必担心。

呈现(Presentation)由索引(显示模式)和对它所依赖的呈现管理器(Presentation Manager)的引用来标识。按照惯例,交互对象的默认表示模式的索引为 0。

在这里插入图片描述

交互对象的不同呈现(Presentations)的计算由继承自 PrsMgr_PresentableObject::Compute 函数的 Compute 函数完成。PresentationManager 在可视化或更新请求时自动调用它们。

如果要创建自己的交互对象类型,则必须通过以下方式之一实现 Compute 函数:

对于 3D:

void PackageName_ClassName::Compute (const Handle(PrsMgr_PresentationManager)& thePresentationManager,
                                     const Handle(Prs3d_Presentation)& thePresentation,
                                     const Standard_Integer theMode);

对于 3D 中的隐线消除(hidden line removal) (HLR)模式:

void PackageName_ClassName::Compute (const Handle(Prs3d_Projector)& theProjector,
                                     const Handle(Prs3d_Presentation)& thePresentation);

隐线消除(Hidden Line Removal)

视图可以有两种状态:正常模式或计算模式(隐线消除(Hidden Line Removal)模式)。当后者处于活动状态时,视图将查找以正常模式显示的所有呈现(presentations),这些呈现(presentations)被标记为接受 HLR 模式。内部机制允许调用交互对象自己的 Compute,即投影函数。

按照约定,交互对象接受或拒绝 HLR 模式的表示形式。可以通过以下两种方式之一进行此声明:

  • 使用枚举 PrsMgr_TypeOfPresentation3d 的值之一进行初始化:
    • PrsMgr_TOP_AllView
    • PrsMgr_TOP_ProjectorDependent
  • 稍后通过使用函数 PrsMgr_PresentableObject::SetTypeOfPresentation

AIS_Shape 类是一个支持 HLR 表示形式的交互对象的示例。HLR 算法的类型存储在形状的 Prs3d_Drawer 中。它是 Prs3d_TypeOfHLR 枚举的值,可以设置为:

  • Prs3d_TOH_PolyAlgo 基于形状三角化的多边形算法;
  • Prs3d_TOH_Algo 适用于形状真实几何形状的精确算法;
  • Prs3d_TOH_NotSet 如果没有为给定的交互对象实例设置算法类型,则为 Prs3d_TOH_NotSet。

可以通过调用 AIS_Shape::SetTypeOfHLR() 方法来更改用于 AIS_Shape 的 HLR 算法的类型。当前的 HLR 算法类型可以使用 AIS_Shape::TypeOfHLR() 方法获取。

这些方法从 AIS_Shape 的 drawer 中获取值。如果 Prs3d_Drawer 中的 HLR 算法类型设置为 Prs3d_TOH_NotSet,则 Prs3d_Drawer 将从 AIS_InteractiveContext 的默认 drawer 中获取值。因此,可以更改所有新显示的交互对象使用的默认 HLR 算法。存储在上下文 drawer 中的 HLR 算法类型的值可以是Prs3d_TOH_AlgoPrs3d_TOH_PolyAlgo。多边形算法是默认算法。

呈现模式(Presentation modes)

AIS 中有四种类型的交互对象:

  • “构造元素”或基准(Datum)
  • 关系(尺寸(dimensions)和约束)
  • 对象
  • None 类型(当对象为未知类型时)

在这些类别中,可以通过签名(索引)获得额外的特征。默认情况下,交互对象的类型为 NONE,签名为 0 (等效于 NONE)。如果要为交互对象提供特定类型和签名,则必须重新定义两个虚函数:

  • AIS_InteractiveObject::Type
  • AIS_InteractiveObject::Signature

请注意,AIS 中提供的“标准”对象已使用某些签名(请参阅标准交互对象类列表)。

交互上下文可以具有交互对象集的默认表示模式。给定的对象类可能不接受此模式。因此,若要获取有关此类的信息,必须使用虚函数 AIS_InteractiveObject::AcceptDisplayMode

显示模式

函数 AIS_InteractiveContext::SetDisplayModeAIS_InteractiveContext::UnsetDisplayMode 允许为对象设置自定义显示模式,该模式可能与交互上下文建议的模式不同。

高亮模式

在动态检测中,由交互上下文回显的呈现(presentation),默认是屏幕上已有的呈现(presentation)。

函数 AIS_InteractiveObject::SetHilightModeAIS_InteractiveObject::UnsetHilightMode 允许指定用于突出显示的显示模式(所谓的高亮模式),该模式的有效性独立于对象的活动表示形式。这种选择是暂时的还是确定的都没有区别。

请注意,相同的呈现(以及相同的高亮模式)用于突出显示检测到的对象和突出显示选中的对象,后者使用特殊的选择颜色绘制(请参阅与交互上下文服务相关的部分)。

例如,你想系统地高亮显示形状的线框表示 —— 不考虑它可视化时是在线框呈现中还是带有阴影。因此,在交互对象的构造函数中将高亮模式设置为 0。不要忘记在 Compute 函数中实现这种表示模式。

无限状态(Infinite Status)

如果不希望对象受到 FitAll 视图的影响,则必须将其声明为 infinite;可以使用 AIS_InteractiveObject::SetInfiniteStateAIS_InteractiveObject::IsInfinite 函数取消其 “infinite” 状态。

让我们以名为 IShape 的类为例,该类表示一个交互对象:

myPk_IShape::myPk_IShape (const TopoDS_Shape& theShape, PrsMgr_TypeOfPresentation theType)
: AIS_InteractiveObject (theType), myShape (theShape) { SetHilightMode (0); }
Standard_Boolean myPk_IShape::AcceptDisplayMode (const Standard_Integer theMode) const
{
  return theMode == 0 || theMode == 1;
}
void myPk_IShape::Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
                           const Handle(Prs3d_Presentation)& thePrs,
                           const Standard_Integer theMode)
{
  switch (theMode)
  {
    // algo for calculation of wireframe presentation
    case 0: StdPrs_WFDeflectionShape::Add (thePrs, myShape, myDrawer); return;
    // algo for calculation of shading presentation
    case 1: StdPrs_ShadedShape::Add (thePrs, myShape, myDrawer); return;
  }
}
void myPk_IShape::Compute (const Handle(Prs3d_Projector)& theProjector,
                           const Handle(Prs3d_Presentation)& thePrs)
{
  // Hidden line mode calculation algorithm
  StdPrs_HLRPolyShape::Add (thePrs, myShape, myDrawer, theProjector);
}  

选择(Selection)

一个交互对象可以有不定数量的选择模式,每种模式都表示“分解”为敏感的基元(primitives)。每个基元(primitive)都有一个所有者SelectMgr_EntityOwner),它允许识别已检测到的确切交互对象或形状(请参阅 选择 章节)。

与给定模式相对应的敏感基元集存放在 SelectionSelectMgr_Selection) 中。

每种选择模式都由一个索引标识。按照惯例,允许我们完整地掌握交互对象的默认选择模式是模式 0。但是,可以使用方法 SelectMgr_SelectableObject::setGlobalSelMode() 在自定义交互式对象中对其进行修改。

选择基元(或敏感实体)的计算是在虚函数 ComputeSelection 中完成的。应使用函数 AIS_InteractiveObject::ComputeSelection 为假定具有不同选择模式的每种类型的交互对象实现它。在选择章节中对该功能的机制和实现方式进行了详细说明。

对于 OCCT 中使用最广泛的交互对象 - AIS_Shape(按顶点,按边等选择),有一些选择模式计算的示例。若要创建与 AIS_Shape 具有相同的选择行为的新交互对象类(如顶点和边),必须重新定义虚函数 AIS_InteractiveObject::AcceptShapeDecomposition

图形属性

图形属性管理器,或 Prs3d_Drawer,存储特定交互对象和由交互上下文控制的交互对象的图形属性。

最初,所有 drawer 属性都使用预定义的值填充,这些值将定义默认的 3D 对象外观。当一个交互对象被可视化时,首先从它自己的 drawer 中获取所需的图形属性,如果存在的话,如果该类型对象不存在特定的 drawer,则从上下文 drawer 中获取所需的图形属性。

有关图形属性,请记住以下几点:

  • 每个交互对象都可以有自己的可视化属性。
  • 默认情况下,交互对象采用可视化上下文的图形属性(可视化模式、用于呈现计算的偏差值、等值参数的数量、颜色、线的类型、材料等)
  • AIS_InteractiveObject 抽象类中,包括颜色、线条粗细、材质和透明度在内的标准属性已获得特权。因此,存在一定数量的虚函数,允许操作这些属性。每个新的交互式对象类都可以重新定义这些函数并更改类的行为。

在这里插入图片描述

以下虚函数提供颜色、宽度、材质和透明度的设置:

  • AIS_InteractiveObject::UnsetColor
  • AIS_InteractiveObject::SetWidth
  • AIS_InteractiveObject::UnsetWidth
  • AIS_InteractiveObject::SetMaterial
  • AIS_InteractiveObject::UnsetMaterial
  • AIS_InteractiveObject::SetTransparency
  • AIS_InteractiveObject::UnsetTransparency

这些方法可以用作以常用方式分配属性的快捷方式,但结果可能不可用。某些交互式对象可能根本不实现这些方法,或者只实现其中的子集。直接修改 AIS_InteractiveObject::Attributes 返回的 Prs3d_Drawer 属性可用于更精确和可预测的配置。

重要的是要知道哪些函数可能意味着重新计算对象的呈现。如果要更新交互对象的呈现模式,则来自 PrsMgr_PresentableObject 的标志会指示这一点。可以使用 AIS_InteractiveContext 中的 DisplayRedisplay 函数更新模式。

补充服务

当您对交互对象使用补充服务时,请特别注意以下情况。

更改交互对象的位置

以下函数允许在视图中“移动”交互对象的表示(representation)和选择(selection),而无需重新计算(和修改原始形状)。

  • AIS_InteractiveContext::SetLocation
  • AIS_InteractiveContext::ResetLocation
  • AIS_InteractiveContext::HasLocation
  • AIS_InteractiveContext::Location

将交互对象连接到应用实体

每个交互对象都具有允许以 Transient 形式将其归属于 GetOwner 的函数。

  • AIS_InteractiveObject::SetOwner
  • AIS_InteractiveObject::HasOwner
  • AIS_InteractiveObject::GetOwner

因此,交互对象可以与应用实体关联或不关联,而不会影响其行为。

注意:不要被其他类型的所有者混淆 - SelectMgr_EntityOwner 用于识别对象或对象本身的可选部分。

解析重合拓扑

由于三维图形坐标的精度具有有限的分辨率,拓扑对象的元素可以重合,从而产生一些元素一个接一个地“弹出”的效果。

对于两个或多个交互对象的元素重合的问题,您可以应用多边形偏移。它是一种图形计算偏移或深度缓冲区偏移,允许您在不更改其坐标的情况下排列元素(通过修改其深度值)。接受这种偏移的图形元素是实心多边形或显示为边界线和点。通过设置适当的内部样式,可以将多边形显示为线或点。

AIS_InteractiveObject::SetPolygonOffsetsAIS_InteractiveContext::SetPolygonOffsets 方法允许设置多边形偏移。

对象层次结构

每个 PrsMgr_PresentableObject 都有一个名为 myChildren 的对象列表。PrsMgr_PresentableObject 的任何转换也适用于其子项。此层次结构不会传播到 Graphic3d 级别及更低级别。

PrsMgr_PresentableObject 将其组合(根据层次结构)转换向下发送到 Graphic3d_Structure。结构的材料不受层次结构的影响。

对象层次结构可以通过以下 API 调用进行控制:

  • PrsMgr_PresentableObject::AddChild
  • PrsMgr_PresentableObject::RemoveChild

实例化

实例化的概念按如下方式操作对象层次结构:

  • 实例由分隔的 AIS 对象表示。
  • 实例不计算任何呈现。

AIS_ConnectedInteractiveAIS_MultipleConnectedInteractive 用于实现这个概念。

AIS_ConnectedInteractive 是一个对象实例,它重用连接对象的几何图形,但有自己的变换和可见性标志。此连接向下传播到 OpenGl 级别,即 OpenGl_StructureOpenGl_Structure 只能连接到单个其他结构。

AIS_ConnectedInteractive 通常可以引用任何 AIS_InteractiveObject。当它被引用到另一个 AIS_ConnectedInteractive 时,它只是复制引用。

AIS_MultipleConnectedInteractive 表示一个程序集,该程序集没有自己的表示形式。这些程序集能够参与对象层次结构,并用于处理一组分组的实例化对象。在选择方面,它表现为单个对象。它将高级转换应用于所有子元素,因为它位于层次结构的上方。

所有 AIS_MultipleConnectedInteractive 都可以有子程序集。如果一个程序集附加到另一个程序集,则执行对象实例树的深层复制。

请注意,AIS_ConnectedInteractive 不能引用 AIS_MultipleConnectedInteractiveAIS_ConnectedInteractive 复制源对象的敏感实体以供选择,不像 AIS_MultipleConnectedInteractive 重用源对象的实体。

实例可以通过以下 DRAW 命令进行控制:

  • vconnect :从输入对象和位置创建和显示 AIS_MultipleConnectedInteractive 对象。
  • vconnectto :创建具有给定位置的对象实例。
  • vdisconnect :断开所有对象与程序集的连接,或按名称或编号断开对象的连接。
  • vaddconnected :将对象添加到程序集。
  • vlistconnected :列出程序集中的对象。

请看下面的例子:

pload MODELING VISUALIZATION
vinit
psphere s 1
vdisplay s
vconnectto s2 3 0 0 s  # make instance
vfit

了解如何使用代理 OpenGl_Structure 来表示实例:

在这里插入图片描述

不必为了创建实例而显示原始对象。此外,选择可以正确处理实例的转换:

pload MODELING VISUALIZATION
vinit
psphere s 1
psphere p 0.5
vdisplay s             # p is not displayed
vsetloc s -2 0 0
vconnect x 3 0 0 s p   # make assembly
vfit

在这里插入图片描述

下面是涉及子组件的更复杂层次结构的示例:

pload MODELING VISUALIZATION
vinit
box b 1 1 1
psphere s 0.5
vdisplay b s
vsetlocation s 0 2.5 0
box d 0.5 0.5 3
box d2 0.5 3 0.5
vdisplay d d2
vconnectto b1 -2 0 0 b
vconnect z 2 0 0 b s
vconnect z2 4 0 0 d d2
vconnect z3 6 0 0 z z2
vfit

交互上下文

规则

交互上下文允许以透明的方式管理一个或多个查看器中交互对象的图形和 可选择(selectable) 行为。大多数允许修改交互对象属性的函数,以及上一章中介绍的函数,将在这里再次介绍。

有一个基本规则需要遵循:对 Context 已知的交互对象的修改,必须使用 Context 函数来完成。如果交互对象尚未加载到交互上下文中,则只能直接调用可用于该对象的函数。

Handle(AIS_Shape) aShapePrs = new AIS_Shape (theShape);
myIntContext->Display (aShapePrs, AIS_Shaded, 0, false, aShapePrs->AcceptShapeDecomposition());
myIntContext->SetColor(aShapePrs, Quantity_NOC_RED);

你也可以写

Handle(AIS_Shape) aShapePrs = new AIS_Shape (theShape);
aShapePrs->SetColor (Quantity_NOC_RED);
aShapePrs->SetDisplayMode (AIS_Shaded);
myIntContext->Display (aShapePrs);

功能组

“中性点”(Neutral Point)“局部选择”(Local Selection) 构成了 交互上下文(Interactive Context) 的两种操作模式或状态,而交互上下文是引导可视化和选择的中心实体。“中性点”(Neutral Point) 是默认模式,它允许轻松可视化和选择已加载到上下文中的交互对象。激活特定对象的 “局部选择”(Local Selection) 允许选择其子部件。

交互上下文的管理

一个交互对象可以具有一定数量的特定图形属性,例如可视化模式、颜色和材质。相应地,交互上下文具有一组图形属性,即 Drawer,默认情况下,该属性对于它所控制的对象有效。可视化交互对象时,首先从对象自己的 Drawer(如果存在)中获取所需的图形属性,否则从上下文 Drawer 中获取。

以下可调整设置允许个性化呈现和选择的行为:

  • 默认 Drawer,包含可以被交互对象使用的所有颜色和线条属性,这些对象没有自己的属性
  • 交互对象的默认可视化模式。默认:模式 0
  • 突出显示鼠标移动检测到的实体的颜色。默认:Quantity_NOC_CYAN1
  • 预选颜色。默认:Quantity_NOC_GREEN
  • 选择颜色(单击检测到的对象时)。默认:Quantity_NOC_GRAY80

所有这些设置都可以通过适当的 AIS_InteractiveContext 函数进行修改。当你更改与上下文相关的图形属性(例如可视化模式)时,所有没有相应属性的交互对象都将被更新。

让我们检查两个交互对象的情况:theObj1theObj2

theCtx->Display (theObj1, false);
theCtx->Display (theObj2, true);  // TRUE for viewer update
theCtx->SetDisplayMode (theObj1, 3, false);
theCtx->SetDisplayMode (2, true);
// theObj2 is visualized in mode 2 (if it accepts this mode)
// theObj1 stays visualized in its mode 3

PrsMgr_PresentationManagerSelectMgr_ViewerSelector3d 用于管理当前交互对象的呈现和选择,它们与主查看器(Viewer)相关联。

警告!不要在实际代码中使用整数值(如上面的示例所示) - 请改用适当的枚举!每个可呈现对象都有独立的支持显示和选择模式列表;例如,AIS_DisplayMode 枚举仅适用于 AIS_Shape 呈现。

局部选择(Local Selection)

选择模式

“局部选择”由索引(选择模式)定义。应在该类的文档中检查由特定交互对象实现的选择模式及其含义。例如,请参阅MeshVS_Mesh 对象的 MeshVS_SelectionModeFlags

AIS_Shape 是最常用的交互对象。它提供了 API 来管理对形状的组成元素的选择操作(选择顶点、边、面等)。特定形状类型 (TopAbs_ShapeEnum) 的选择模式由方法 AIS_Shape::SelectionMode() 返回。

不带 Selection Mode 参数的 AIS_InteractiveContext::Display() 方法激活对象的默认选择模式(Selection Mode)。AIS_InteractiveContext::Activate()AIS_InteractiveContext::Deactivate() 方法激活和停用特定的选择模式。

可以同时激活多个选择模式(但用于选择整个对象的默认 0 模式是独占的 - 它不能与其他模式组合使用)。可以使用函数 AIS_InteractiveContext::ActivatedModes 检索活动模式列表。

过滤器(Filters)

要定义动态检测环境,可以使用标准过滤器类或创建自己的过滤器类。过滤器询问敏感基元的所有者,以确定它是否具有所需的特征。如果它的回答是肯定的,它就会被保留。否则,它将被拒绝。

对象的根类是 SelectMgr_Filter。其背后的原理很简单:过滤器通过选择器回答“OK”来测试所有者(SelectMgr_EntityOwner)是否检测到鼠标位置。如果是,则保留,否则被拒绝。您可以通过实现延迟函数 SelectMgr_Filter::IsOk() 来创建过滤器对象的自定义类。

SelectMgr 中,还有组合过滤器(AND 过滤器、OR 过滤器),它允许组合多个过滤器。在交互上下文中,您添加的所有过滤器都存储在 OR 过滤器中(如果至少有一个过滤器回答 OK,则回答 OK)。

有一些标准过滤器,它们已经在几个包中实现:

有几个函数可以操作过滤器:

  • AIS_InteractiveContext::AddFilter 添加作为参数传递的过滤器。
  • AIS_InteractiveContext::RemoveFilter 删除作为参数传递的过滤器。
  • AIS_InteractiveContext::RemoveFilters 删除所有存在的过滤器。
  • AIS_InteractiveContext::Filters 获取上下文中处于活动状态的过滤器列表。

例子

// shading visualization mode, no specific mode, authorization for decomposition into sub-shapes
const TopoDS_Shape theShape;
Handle(AIS_Shape) aShapePrs = new AIS_Shape (theShape);
myContext->Display (aShapePrs, AIS_Shaded, -1, true, true);
// activates decomposition of shapes into faces
const int aSubShapeSelMode = AIS_Shape::SelectionMode (TopAbs_Face);
myContext->Activate (aShapePrs, aSubShapeSelMode);
Handle(StdSelect_FaceFilter) aFil1 = new StdSelect_FaceFilter (StdSelect_Revol);
Handle(StdSelect_FaceFilter) aFil2 = new StdSelect_FaceFilter (StdSelect_Plane);
myContext->AddFilter (aFil1);
myContext->AddFilter (aFil2);
// only faces of revolution or planar faces will be selected
myContext->MoveTo (thePixelX, thePixelY, myView, true);

选择(Selection)

动态检测和选择以直接的方式生效。只有几个约定和函数需要熟悉:

  • AIS_InteractiveContext::MoveTo – 将鼠标位置传递给交互上下文选择器。
  • AIS_InteractiveContext::SelectDetected – 存储在上次 MoveTo 中检测到的内容。更改先前选定的对象。根据选择方案,选择被丰富、替换或其他。
  • AIS_InteractiveContext::SelectPoint/SelectRectangle/SelectPolygon – 将选择应用于点、矩形或周围区域。更改先前选定的对象。根据选择方案,选择被丰富、替换或其他。

检测到的和选定的实体的突出显示由交互上下文自动管理。高亮颜色是上面处理的颜色。不过,如果您想自己管理此部分,您可以断开此自动模式:

AIS_InteractiveContext::SetAutomaticHilight
AIS_InteractiveContext::AutomaticHilight

您可以通过移动鼠标来询问交互上下文。可以使用以下功能:

  • AIS_InteractiveContext::HasDetected – 检查是否存在检测到的实体;
  • AIS_InteractiveContext::DetectedOwner – 返回(当前突出显示的)检测到的实体。

在使用 Select 函数后,您可以浏览选择列表。可以使用以下功能:

  • AIS_InteractiveContext::InitSelected – 初始化迭代器;
  • AIS_InteractiveContext::MoreSelected – 检查迭代器是否有效;
  • AIS_InteractiveContext::NextSelected – 将迭代器移动到下一个位置;
  • AIS_InteractiveContext::SelectedOwner – 返回当前迭代器位置的实体。

所有者对象 SelectMgr_EntityOwner 是标识查看器中可选择实体的关键对象(由方法 AIS_InteractiveContext::DetectedOwnerAIS_InteractiveContext::SelectedOwner 返回)。交互对象本身可以通过方法 SelectMgr_EntityOwner::Selectable 进行检索,而识别子部件取决于交互对象的类型。如果是 AIS_Shape,则通过方法 StdSelect_BRepOwner::Shape 返回 (sub)shape。

例子

for (myAISCtx->InitSelected(); myAISCtx->MoreSelected(); myAISCtx->NextSelected())
{
  Handle(SelectMgr_EntityOwner) anOwner = myAISCtx->SelectedOwner();
  Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (anOwner->Selectable());
  if (Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast (anOwner))
  {
    // to be able to use the picked shape
    TopoDS_Shape aShape = aBRepOwner->Shape();
  }
}

选择方案(Selection schemes)

AIS_InteractiveContextSelect* 方法接受某些选择方案作为参数。下表描述了可用的选择方案。

在这里插入图片描述

标准交互对象类

交互对象是连接图形表示和基础参考几何图形的可选择和可查看对象。

它们分为四种类型:

  • 基准(Datum) – 构造几何元素;
  • 关系(Relation) – 对交互形状和相应参考几何图形的约束;
  • 对象(Object) – 拓扑形状或形状之间的连接;
  • None – 一个标记,它不是消除对象,而是告诉应用程序进一步查找,直到它在生成中找到可接受的对象定义。

在这些类别中,有可能通过签名进行额外的特性描述。该签名为进一步特性描述提供了索引。默认情况下,交互对象具有 None 类型和 0 签名(相当于 None)。如果要为交互对象提供特定类型和签名,必须重新定义两个虚方法:TypeSignature

基准(Datum)

基准(Datum) 将直线、圆、点、三面体、平面三面体、平面和轴等构造图元组合在一起。

AIS_PointAIS_AxisAIS_LineAIS_CircleAIS_PlaneAIS_Trihedron 有四种选择模式:

当您激活其中一种模式时,您可以选择以下类型的 AIS 对象:

AIS_PlaneTrihedron 提供三种选择模式:

  • 模式 0:选择整个三面体
  • 模式 1:选择三面体的原点
  • 模式 2:选择轴 - 与三面体的注释相同

对于平面和三面体的呈现,默认长度单位为毫米,轴表示的默认值为 10。要修改这些尺寸,必须临时恢复对象 Drawer。从中获取 DatumAspect() 并更改值 FirstAxisLength。最后,重新计算呈现。

对象(Object)

对象(Object) 类型包括拓扑形状和形状之间的连接。

AIS_Shape 有两种可视化模式:

AIS_ConnectedInteractive 是一个连接到另一个交互对象引用的交互对象,它位于查看器中的其他位置,因此可以不计算呈现和选择,而是从对象引用中推断出它们。AIS_MultipleConnectedInteractive 是一个连接到交互对象列表的对象(也可以是被连接对象;它不需要占用大量内存的呈现计算)。

MeshVS_Mesh 是一个表示网格的交互对象,它有一个提供几何信息(节点、元素)的数据源,并且可以使用自定义呈现构建器从源数据构建。

AIS_ColoredShape 类允许对 TopoDS_Shape 对象及其子形状使用自定义颜色和线宽。

AIS_ColoredShape aColoredShape = new AIS_ColoredShape (theShape);
// setup color of entire shape
aColoredShape->SetColor (Quantity_NOC_RED);
// setup line width of entire shape
aColoredShape->SetWidth (1.0);
// set transparency value
aColoredShape->SetTransparency (0.5);
// customize color of specified sub-shape
aColoredShape->SetCustomColor (theSubShape, Quantity_NOC_BLUE1);
// customize line width of specified sub-shape
aColoredShape->SetCustomWidth (theSubShape, 0.25);

呈现类 AIS_PointCloud 可用于高效绘制大型任意彩色点集。它使用 Graphic3d_ArrayOfPoints 将点数据传递到 OpenGl 图形驱动程序中,以将设定点绘制为“点精灵”数组。点数据被打包到顶点缓冲区对象中以提高性能。

  • 用于绘制点的点标记的类型可以指定为呈现外观。
  • 该呈现通过可视化点集的边界框提供选择。它支持两种显示/高亮模式:点或边界框。

在这里插入图片描述

随机的彩色点云

例子:

Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (2000, Standard_True);
aPoints->AddVertex (gp_Pnt(-40.0, -40.0, -40.0), Quantity_Color (Quantity_NOC_BLUE1));
aPoints->AddVertex (gp_Pnt (40.0,  40.0,  40.0), Quantity_Color (Quantity_NOC_BLUE2));
Handle(AIS_PointCloud) aPntCloud = new AIS_PointCloud();
aPntCloud->SetPoints (aPoints);

绘制命令 vpointcloud 根据形状三角剖分构建点云。该命令还可以绘制球面或具有大量点(超过 100 万)的体(volume)。

关系(Relations)

关系(Relation) 由对一个或多个交互形状的约束以及相应的参考几何图形组成。例如,您可能希望在并行关系中约束两条边。该约束本身被视为一个对象,并显示为敏感基元。这采用标有 || 符号的垂直箭头的图形形式,并位于两条边之间。

PrsDim 提供以下关系:

关系列表并非详尽无遗。

尺寸(Dimensions)

MeshVS_Mesh

MeshVS_Mesh 是一个表示网格的交互对象。这个对象与 AIS_Shape 不同,因为它的几何数据由描述对象节点和元素的数据源 MeshVS_DataSource 支持。因此,您可以提供自己的数据源。

但是,DataSource 不提供有关属性(例如节点颜色)的任何信息,但您可以通过选择适当的呈现生成器以特殊方式应用它们。

MeshVS_Mesh 的呈现是使用呈现构建器 MeshVS_PrsBuilder 构建的。您可以在构建器之间进行选择,以不同的方式表示对象。此外,您可以重新定义基础构建器类并提供自己的呈现构建器。

您可以使用以下方法添加/删除构建器:

MeshVS_Mesh::AddBuilder (const Handle(MeshVS_PrsBuilder)& theBuilder, Standard_Boolean theToTreatAsHilighter);
MeshVS_Mesh::RemoveBuilder (const Standard_Integer theIndex);
MeshVS_Mesh::RemoveBuilderById (const Standard_Integer theId);

有一组用于 MeshVS_Mesh 的保留的显示和高亮模式标志。模式值是一个位数,允许选择其他显示参数并组合以下模式标志,允许以线框、着色和收缩模式显示网格:

MeshVS_DMF_WireFrame
MeshVS_DMF_Shading
MeshVS_DMF_Shrink

还可以使用以下方法在线框、着色或收缩模式下显示变形的网格:

MeshVS_DMF_DeformedPrsWireFrame
MeshVS_DMF_DeformedPrsShading
MeshVS_DMF_DeformedPrsShrink

以下方法表示不同类型的数据:

MeshVS_DMF_VectorDataPrs
MeshVS_DMF_NodalColorDataPrs
MeshVS_DMF_ElementalColorDataPrs
MeshVS_DMF_TextDataPrs
MeshVS_DMF_EntitiesWithData

以下方法提供选择和突出显示:

MeshVS_DMF_SelectionPrs
MeshVS_DMF_HilightPrs

MeshVS_DMF_User 是用户定义的模式。

这些值将由呈现构建器使用。还有一组选择模式标志,可以按位组合进行分组:

  • MeshVS_SMF_0D
  • MeshVS_SMF_Link
  • MeshVS_SMF_Face
  • MeshVS_SMF_Volume
  • MeshVS_SMF_Element – 组 0D、Link、Face 和 Volume 作为位掩码
  • MeshVS_SMF_Node
  • MeshVS_SMF_All – 组 Element 和 Node 作为位掩码
  • MeshVS_SMF_Mesh
  • MeshVS_SMF_Group

例如,这样的对象可用于显示对象并以 STL 文件格式存储:

// read the data and create a data source
Handle(Poly_Triangulation) aSTLMesh = RWStl::ReadFile (aFileName);
Handle(XSDRAWSTLVRML_DataSource) aDataSource = new XSDRAWSTLVRML_DataSource (aSTLMesh);
// create mesh
Handle(MeshVS_Mesh) aMeshPrs = new MeshVS();
aMeshPrs->SetDataSource (aDataSource);
// use default presentation builder
Handle(MeshVS_MeshPrsBuilder) aBuilder = new MeshVS_MeshPrsBuilder (aMeshPrs);
aMeshPrs->AddBuilder (aBuilder, true);

MeshVS_NodalColorPrsBuilder 允许在网格上映射颜色缩放纹理。为此,您应该为色阶定义一个颜色映射表,将此映射传递给呈现构建器,并为每个节点定义一个 0.0 - 1.0 范围内的适当值。以下示例演示了如何执行此操作(检查视图是否已设置为显示纹理):

// assign nodal builder to the mesh
Handle(MeshVS_NodalColorPrsBuilder) aBuilder = new MeshVS_NodalColorPrsBuilder (theMeshPrs, MeshVS_DMF_NodalColorDataPrs | MeshVS_DMF_OCCMask);
aBuilder->UseTexture (true);
// prepare color map
Aspect_SequenceOfColor aColorMap;
aColorMap.Append (Quantity_NOC_RED);
aColorMap.Append (Quantity_NOC_BLUE1);
// assign color scale map  values (0..1) to nodes
TColStd_DataMapOfIntegerReal aScaleMap;
...
// iterate through the  nodes and add an node id and an appropriate value to the map
aScaleMap.Bind (anId, aValue);
// pass color map and color scale values to the builder
aBuilder->SetColorMap (aColorMap);
aBuilder->SetInvalidColor (Quantity_NOC_BLACK);
aBuilder->SetTextureCoords (aScaleMap);
aMesh->AddBuilder (aBuilder, true);

动态选择(Dynamic Selection)

动态选择通过分解敏感基元(sensitive primitives)(将要检测和突出显示的形状的子部分)来表示要选择的拓扑形状。这些基元的集合由强大的三级 BVH 树选择算法处理。

有关算法和使用示例的更多详细信息,请参阅选择章节。

3D 呈现(3D Presentations)

3D 术语表

  • Group(组) – 一组基元和这些基元上的属性。基元和属性可以添加到组中,但不能从中移除,除非全局删除。一个组可以有一个选取标识。
  • Light(光源) 有五种光源 – 环境光、前照灯、定向光源、位置光源和点光源。
  • Primitive(基元) – 可绘制元素。它在 3D 空间中有一个定义。基元可以是线、面、文本或标记。显示后,标记和文本的大小保持不变。可以修改线和面,例如缩放。属性是在组内设置的。基元必须存储在一个组中。
  • Structure(结构) – 管理一组组(group)。这些组是相互排斥的。可以编辑结构,添加或删除组。一个结构可以引用其他结构来形成层次结构。它有一个默认的(恒等)转换,并且可以对其应用其他转换(旋转、平移、缩放等)。每个结构都有一个与之关联的显示优先级,该优先级决定了在 3D 查看器中重绘的顺序。
  • View(视图) – 由视图方向、视图映射和上下文视图定义。
  • Viewer(查看器) – 管理一组视图。
  • View orientation(视图方向) – 定义观察者根据视图参考坐标查看场景的方式。
  • View mapping(视图映射) – 定义从视图参考坐标到归一化投影坐标的变换。这遵循 Phigs 方案。
  • Z-Buffering – 一种仅在着色模式下移除隐藏表面的形式。对于处于着色模式的视图,此选项始终处于活动状态,并且不能被抑制。

图形基元(Graphic primitives)

Graphic3d 包用于在 3D 查看器中创建 3D 图形对象。这些称为 结构(structures) 的对象由基元组(如线段、三角形、文本和标记)和属性(如颜色、透明度、反射、线型、线宽和文本字体)组成。组是结构中最小的可编辑元素。可以将变换应用于结构。结构可以连接起来形成由变换组成的结构树。结构由查看器(viewer)全局操纵。

图形结构可以是:

  • Displayed (显示)
  • Highlighted (高亮)
  • Erased (删除)
  • Transformed (变换)
  • 连接以形成由变换创建的结构的树状层次结构

有以下类:

  • 线、面、标记、文本、材质的视觉属性
  • 向量和顶点 (Vectors and vertices)
  • 图形对象、组和结构

结构层次(Structure hierarchies)

根是结构层次或结构网络的顶部。父结构的属性被传递给其后代。后代结构的属性不影响父结构。不支持递归结构网络。

图形基元(Graphic primitives)

  • Markers (标记)
    • 有一个或多个顶点
    • 有一个类型、一个比例因子和一个颜色
    • 具有独立于变换的大小、形状和方向
  • Triangulation (三角剖分)
    • 至少有三个顶点
    • 为着色定义了节点法线
    • 具有内部属性 – 风格、颜色、正反面材质、纹理和反射率
  • Polylines(折线)Segments(线段)
    • 有两个或多个顶点
    • 具有以下属性 – 类型、宽度比例因子、颜色
  • Text (文本)
    • 具有几何和非几何属性
    • 几何属性 – 字符高度、字符向上向量、文本路径、水平和垂直对齐、方向、三维位置、可缩放标志
    • 非几何属性 – 文本字体、字符间距、字符扩展因子、颜色

基元数组(Primitive arrays)

不同类型的基元可以用以下基元数组来表示:

Graphic3d_ArrayOfPrimitives 是这些基元数组的基类。方法集 Graphic3d_ArrayOfPrimitives::AddVertex 允许将顶点及其属性(颜色、法线、纹理坐标)添加到基元数组中。您还可以修改分配给顶点的值,或按顶点索引查询这些值。

下面的示例演示如何定义点数组:

// create an array
Handle(Graphic3d_ArrayOfPoints) anArray = new Graphic3d_ArrayOfPoints (theVerticiesMaxCount);
// add vertices to the array
anArray->AddVertex (10.0, 10.0, 10.0);
anArray->AddVertex (0.0,  10.0, 10.0);
// add the array to the structure
Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
aGroup->AddPrimitiveArray (anArray);
aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect());

如果基元共享相同的顶点(多边形、三角形等),则可以将它们定义为顶点数组的索引。Graphic3d_ArrayOfPrimitives::AddEdge 方法允许通过索引定义基元。此方法在数组的 [1, VertexNumber()] 范围内添加一条“边”。也可以使用方法 Graphic3d_ArrayOfPrimitives::Edge 查询由边定义的顶点。

下面的示例演示如何定义三角形数组:

// create an array
Handle(Graphic3d_ArrayOfTriangles) anArray = new Graphic3d_ArrayOfTriangles (theVerticesMaxCount, theEdgesMaxCount, Graphic3d_ArrayFlags_None);
// add vertices to the array
anArray->AddVertex (-1.0, 0.0, 0.0); // vertex 1
anArray->AddVertex ( 1.0, 0.0, 0.0); // vertex 2
anArray->AddVertex ( 0.0, 1.0, 0.0); // vertex 3
anArray->AddVertex ( 0.0,-1.0, 0.0); // vertex 4
// add edges to the array
anArray->AddEdges (1, 2, 3); // first triangle
anArray->AddEdges (1, 2, 4); // second triangle
// add the array to the structure
Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
aGroup->AddPrimitiveArray (anArray);
aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());

文本基元(Text primitive)

TKOpenGl 工具包使用纹理字体渲染文本标签。Graphic3d 文本基元具有以下特征:

  • 固定大小(不可缩放)或可缩放,
  • 可以旋转到视图平面中的任何角度,
  • 支持 Unicode 字符集。

可以使用 Graphic3d_AspectText3d 属性组定义组的文本属性。若要将任何文本添加到图形结构中,可以使用以下方法:

void Graphic3d_Group::AddText (const Handle(Graphic3d_Text)& theTextParams,
                               const Standard_Boolean theToEvalMinMax);

如果不希望 Graphic3d 结构边界受到文本位置的影响,则可以将 FALSE 作为 ToEvalMinMax 传递。

请注意,文本方向角度可以通过 Graphic3d_AspectText3d 属性来定义。

请参阅示例:

// get the group
Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
// change the text aspect
Handle(Graphic3d_AspectText3d) aTextAspect = new Graphic3d_AspectText3d();
aTextAspect->SetTextZoomable (true);
aTextAspect->SetTextAngle (45.0);
aGroup->SetPrimitivesAspect (aTextAspect);
// add a text primitive to the structure
Handle(Graphic3d_Text) aText = new Graphic3d_Text (16.0f);
aText->SetText ("Text");
aText->SetPosition (gp_Pnt (1, 1, 1));
aGroup->AddText (aText);

材料(Materials)

Graphic3d_MaterialAspect 定义了以下通用材料属性:

  • 透明度(Transparency)
  • 漫反射(Diffuse reflection) – 物体颜色的一个组成部分
  • 环境反射(Ambient reflection)
  • 镜面反射(Specular reflection) – 光源颜色的一个组成部分

确定反射的三种颜色需要以下项目:

  • 颜色
  • 漫反射系数
  • 环境反射系数
  • 镜面反射系数

Phong 着色模型(Graphic3d_TypeOfShadingModel_PhongGraphic3d_TypeOfShadingModel_PhongFacetGraphic3d_TypeOfShadingModel_Gouraud)中使用了常见的材料属性。在 PBR 着色模型(Graphic3d_TypeOfShadingModel_PbrGraphic3d_TypeOfShadingModel_PbrFacet)中,材质属性由以下Graphic3d_PBRMaterial 属性 (Graphic3d_MaterialAspect::PBRMaterial()) 定义:

  • 反照率(主色)
  • 金属因素
  • 粗糙度系数
  • 透明度
  • 折射率

纹理(Textures)

纹理由名称定义。有三种类型的纹理可供选择:

  • 1D
  • 2D
  • 环境映射

自定义着色器(Custom shaders)

OCCT 可视化核心支持 GLSL 着色器。自定义着色器可以通过其 drawer 属性(Graphic3d aspects)分配给通用呈现(presentation)。若要为应用程序中的特定 AIS_Shape 启用自定义着色器,可以使用以下 API 函数:

// Create shader program
Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
// Attach vertex shader
aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX, "<Path to VS>"));
// Attach fragment shader
aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, "<Path to FS>"));
// Set values for custom uniform variables (if they are)
aProgram->PushVariable ("MyColor", Graphic3d_Vec3 (0.0f, 1.0f, 0.0f));
// Set aspect property for specific AIS_Shape
theAISShape->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);

图形属性(Graphic attributes)

Aspect 包概述

Aspect 包为查看器中的图形元素提供类:

  • Groups of graphic attributes(图形属性组)
  • Edges, lines, background(边、线、背景)
  • Window
  • Driver
  • 上述许多的枚举

3D 视图设施(3D view facilities)

概述

V3d 包提供了用于定义 3D 查看器的资源以及附加到此查看器的视图(正交、透视)。该软件包提供了用于操作在屏幕视图中可视化的任何 3D 对象的图形场景的命令。

一组高级命令允许在任何特定视图中单独操作参数和投影结果(旋转、缩放、平移等)以及可视化属性(模式、照明、剪裁等)。

V3d 包基本上是一组由查看器前端的命令指导的工具。该工具集包含用于创建和编辑查看器类的方法,例如:

  • 查看器的默认参数,
  • 视图(正交、透视)、
  • 照明(Lighting)(位置、定向、环境、点光源、前照灯)、
  • 剪裁平面(Clipping planes),
  • 视图、平面、光源、图形结构和拾取器(picks)的实例化序列,
  • 各种封装方法。

编程示例

这个 V3d 包的示例 TEST 程序使用主包 XwGraphic3d 以及辅助包 Visual3d、AspectQuantitymath

// create a default display connection
Handle(Aspect_DisplayConnection) aDispConnection = new Aspect_DisplayConnection();
// create a Graphic Driver
Handle(OpenGl_GraphicDriver) aGraphicDriver = new OpenGl_GraphicDriver (aDispConnection);
// create a Viewer to this Driver
Handle(V3d_Viewer) aViewer = new V3d_Viewer (aGraphicDriver);
aViewer->SetDefaultBackgroundColor (Quantity_NOC_DARKVIOLET);
// Create a structure in this Viewer
Handle(Graphic3d_Structure) aStruct = new Graphic3d_Structure (aViewer->StructureManager());
aStruct->SetVisual (Graphic3d_TOS_SHADING); // Type of structure
// Create a group of primitives  in this structure
Handle(Graphic3d_Group) aPrsGroup = aStruct->NewGroup();
// Fill this group with one quad of size 100
Handle(Graphic3d_ArrayOfTriangleStrips) aTriangles = new Graphic3d_ArrayOfTriangleStrips (4);
aTriangles->AddVertex (-100./2., -100./2., 0.0);
aTriangles->AddVertex (-100./2.,  100./2., 0.0);
aTriangles->AddVertex ( 100./2., -100./2., 0.0);
aTriangles->AddVertex ( 100./2.,  100./2., 0.0);
Handle(Graphic3d_AspectFillArea3d) anAspects = new Graphic3d_AspectFillArea3d (Aspect_IS_SOLID, Quantity_NOC_RED,
                                                                               Quantity_NOC_RED, Aspect_TOL_SOLID, 1.0f,
                                                                               Graphic3d_NameOfMaterial_Gold, Graphic3d_NameOfMaterial_Gold);
aPrsGroup->SetGroupPrimitivesAspect (anAspects);
aPrsGroup->AddPrimitiveArray (aTriangles);
// Create Ambient and Infinite Lights in this Viewer
Handle(V3d_AmbientLight)     aLight1 = new V3d_AmbientLight (Quantity_NOC_GRAY50);
Handle(V3d_DirectionalLight) aLight2 = new V3d_DirectionalLight (V3d_Zneg, Quantity_NOC_WHITE, true);
aViewer->AddLight (aLight1);
aViewer->AddLight (aLight2);
aViewer->SetLightOn();
// Create a 3D quality  Window with the same DisplayConnection
Handle(Xw_Window) aWindow = new Xw_Window (aDispConnection, "Test V3d", 100, 100, 500, 500);
aWindow->Map(); // Map this Window to this screen
// Create a Perspective  View in this Viewer
Handle(V3d_View) aView = new V3d_View (aViewer);
aView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
// Associate this View with the Window
aView->SetWindow (aWindow);
// Display presentation in this View
aStruct->Display();
// Finally update the Visualization in this View
aView->Update();
// Fit view to object size
aView->FitAll();

定义查看参数(Define viewing parameters)

OCCT V3d_View 中的视图投影和方向由相机(camera)驱动。相机(camera)计算并提供投影和视图方向矩阵,供 OpenGL 渲染。允许用户控制所有投影参数。相机(camera)由以下属性定义:

  • Eye(眼睛) – 定义观察者(相机)位置。确保眼点(Eye point)永远不会位于前裁平面和后裁平面之间。
  • Center(中心) – 定义视图参考坐标的原点(相机对准的位置)。
  • Direction(方向) – 定义相机视图的方向(从眼睛(Eye)到中心(Center))。
  • Distance(距离) – 定义眼睛(Eye)和中心(Center)之间的距离。
  • Front Plane (前平面) – 定义视图参考坐标系中前裁剪平面的位置。
  • Back Plane (后平面) – 定义视图参考坐标系中后裁剪平面的位置。
  • ZNear – 定义眼睛(Eye)和前平面(Front plane)之间的距离。
  • ZFar – 定义眼睛(Eye)和后平面(Back plane)之间的距离。

最常见的视图操作(平移、缩放、旋转)是作为 V3d_View 类的便捷方法或通过 AIS_ViewController 工具实现的。但是,应用程序开发人员也可以直接使用 Graphic3d_Camera 类。例:

// rotate camera by X axis on 30.0 degrees
gp_Trsf aTrsf;
aTrsf.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Dir (1.0, 0.0, 0.0)), M_PI / 4.0);
aView->Camera()->Transform (aTrsf);

正交投影(Orthographic Projection)

在这里插入图片描述

透视投影和正交投影

以下代码配置相机以进行正交渲染:

// Create an orthographic View in this Viewer
Handle(V3d_View) aView = new V3d_View (theViewer);
aView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
aView->Update(); // update the Visualization in this View

透视投影(Perspective Projection)

Field of view (FOVy)(视场) – 以 y 轴定义相机(camera)视场,单位为度(默认为 45°)。

在这里插入图片描述

透视视锥体 (Perspective frustum)

以下代码配置相机以进行透视渲染:

// Create a perspective View in this Viewer
Handle(V3d_View) aView = new V3d_View (theViewer);
aView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
aView->Update();

立体投影(Stereographic Projection)

IOD – intraocular distance,定义眼内(intraocular)距离(以世界空间单位(world space units)为单位)。

IOD 有两种类型:

  • Graphic3d_Camera::IODType_Absolute:眼内距离(Intraocular distance)定义为绝对值。
  • Graphic3d_Camera::IODType_Relative:眼内距离(Intraocular distance)是相对于相机焦距定义的(作为其系数)。

Field of view (FOV)(视场) – 以 y 轴定义相机(camera)视场,单位为度(默认为 45°)。

ZFocus – 定义到立体焦点的距离。

在这里插入图片描述

立体投影 (Stereographic projection)

要为主动(快门)3D 眼镜启用立体投影,您的工作站应满足以下要求:

  • 显卡应支持四通道缓冲。
  • 您需要主动式 3D 眼镜(LCD 快门眼镜)。
  • 图形驱动程序需要配置为对新创建的 OpenGl 上下文进行四通道缓冲;查看器(viewer)和视图(view)应在此之后创建。

在立体投影模式下,相机准备两个投影矩阵,为左眼和右眼显示不同的立体图像。在非立体相机中,这种效果是不可见的,因为两只眼睛只使用相同的投影。

若要启用四通道缓冲支持,你应该为图形驱动程序 OpenGl_Caps 提供以下设置:

Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver();
OpenGl_Caps& aCaps = aDriver->ChangeOptions();
aCaps.contextStereo = Standard_True;

以下代码配置相机以进行立体渲染:

// Create a Stereographic View in this Viewer
Handle(V3d_View) aView = new V3d_View (theViewer);
aView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
// Change stereo parameters
aView->Camera()->SetIOD (IODType_Absolute, 5.0);
// Finally update the Visualization in this View
aView->Update();

还支持其他 3D 显示,包括隔行扫描被动眼镜和立体眼镜 - 请参阅 Graphic3d_StereoMode 枚举。激活另一个立体显示的示例:

Handle(V3d_View) theView;
theView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
theView->ChangeRenderingParams().StereoParams = Graphic3d_StereoMode_RowInterlaced;

VR/AR 头戴式设备在应用中的支持更为复杂。Aspect_XRSession 类定义了用于处理扩展现实的基本接口。

视图视锥体剔除(View frustum culling)

默认情况下,CPU 端的视锥体剔除算法在 3D 查看器中处于激活状态。该算法允许在渲染阶段跳过相机外部的呈现,从而提供更好的性能。以下功能支持此方法:

  • Graphic3d_Structure::CalculateBoundBox() 用于计算考虑其变换的呈现的轴对齐边界框。
  • V3d_View::SetFrustumCulling 启用或禁用指定视图的视锥体剔除。
  • Graphic3d_BvhCStructureSetGraphic3d_CullingTool 处理外部对象的检测和加速结构在视锥体剔除中的使用。
  • BVH_BinnedBuilder 类使用 null 边界框分割多个对象。

视图背景样式(View background styles)

有几种类型的背景样式可用于 V3d_View:纯色、渐变色、图像和环境立方体贴图。

要设置背景为纯色,您可以使用以下方法:

void V3d_View::SetBackgroundColor (const Quantity_Color& theColor);

可以使用以下方法设置渐变背景样式:

void V3d_View::SetBgGradientColors (const Quantity_Color& theColor1,
                                    const Quantity_Color& theColor2,
                                    const Aspect_GradientFillMethod theFillStyle,
                                    const Standard_Boolean theToUpdate = false);

theColor1theColor2 参数定义插值的边界颜色,theFillStyle 参数定义插值的方向。

若要将图像设置为背景并更改背景图像样式,可以使用以下方法:

void V3d_View::SetBackgroundImage (const Standard_CString theFileName,
                                   const Aspect_FillMethod theFillStyle,
                                   const Standard_Boolean theToUpdate = false);

theFileName 参数定义图像文件名及其路径,theFillStyle 参数定义使用图像填充背景的方法。这些方法有:

  • Aspect_FM_NONE – 在默认位置绘制图像;
  • Aspect_FM_CENTERED – 在视图的中心绘制图像;
  • Aspect_FM_TILED – 使用图像平铺视图;
  • Aspect_FM_STRETCH – 将图像拉伸到视图上。

将 3D 场景转储到图像文件中(Dumping a 3D scene into an image file)

视图中显示的 3D 场景可以转储到图像文件中,其分辨率与窗口大小无关(使用屏幕外缓冲区)。V3d_View 有以下用于转储 3D 场景的方法:

Standard_Boolean V3d_View::Dump (const Standard_CString theFile,
                                 const Image_TypeOfImage theBufferType);

将场景转储到具有视图尺寸的图像文件中。栅格图像数据处理算法基于 Image_AlienPixMap 类。支持的扩展名是 “.png”、“.bmp”、“.jpg” 和 FreeImage 库支持的其他扩展名。作为 theBufferType 参数传递的值定义输出图像的缓冲区类型(RGB、RGBA、浮点、RGBF、RGBAF)。如果场景已成功转储,则方法返回 TRUE

Standard_Boolean V3d_View::ToPixMap (Image_PixMap&               theImage,
                                     const V3d_ImageDumpOptions& theParams);

将显示的 3D 场景转储到像素图中,其宽度和高度通过参数结构 theParams 传递。

光线追踪支持(Ray tracing support)

OCCT 可视化通过实时光线追踪技术提供渲染。它允许在通常的光栅化和光线追踪渲染模式之间轻松切换。OCCT 光线追踪的核心是使用 GLSL 着色器编写的。光线追踪有很多特性:

  • 硬阴影(Hard shadows)
  • 折射(Refractions)
  • 反射(Reflection)
  • 透明度(Transparency)
  • 纹理(Texturing)
  • 支持非多边形对象,如线、文本、突出显示、选择。
  • 使用 2 级层次包围体结构(2-level bounding volume hierarchy) (BVH) 进行性能优化。

光线追踪算法是递归的(Whitted 算法)。它采用 BVH 有效的优化结构。该结构为场景几何体准备优化数据,以便进一步实时显示。对于视图操作、选择、动画甚至通过变换对象位置来编辑场景,不需要耗时的 BVH 重新计算。仅当显示对象列表或其几何图形发生更改时,才需要这样做。为了使 BVH 可重复使用,它已被添加到单独的可重用 OCCT 包 TKMath/BVH 中。

用户可以打开/关闭多个光线追踪选项:

  • 最大光线追踪深度
  • 阴影渲染
  • 镜面反射
  • 自适应抗锯齿
  • 透明阴影效果

例:

Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
// specifies rendering mode
aParams.Method = Graphic3d_RM_RAYTRACING;
// maximum ray-tracing depth
aParams.RaytracingDepth = 3;
// enable shadows rendering
aParams.IsShadowEnabled = true;
// enable specular reflections
aParams.IsReflectionEnabled = true;
// enable adaptive anti-aliasing
aParams.IsAntialiasingEnabled = true;
// enable light propagation through transparent media
aParams.IsTransparentShadowEnabled = true;
// update the view
aView->Update();

显示优先级(Display priorities)

结构显示优先级控制绘制结构的顺序。当你显示结构时,请指定其优先级。值越低,显示优先级越低。当显示重新生成时,首先绘制优先级最低的结构。具有相同显示优先级的结构按其显示顺序绘制。OCCT 支持 [0, 10] 范围内的 11 个结构显示优先级。

Z 层支持(Z-layer support)

OCCT 具有称为 z-layer 的深度排列功能。图形呈现可以放入 z-layer 中。通常,此函数可用于在图形应用程序中实现“放在前面(bring to front)”功能。

例:

// set z-layer to an interactive object
Handle(AIS_InteractiveContext) theContext;
Handle(AIS_InteractiveObject) theInterObj;
Standard_Integer anId = -1;
aViewer->AddZLayer (anId);
theContext->SetZLayer (theInterObj, anId);

对于每个 z 层,允许:

  • 启用/禁用图层的深度测试。
  • 启用/禁用图层的深度写入。
  • 启用/禁用深度缓冲区清除。
  • 启用/禁用多边形偏移。

您可以使用 getter 从 V3d_Viewer 获取选项。它返回给定 LayerIdGraphic3d_ZLayerSettings

例:

// change z-layer settings
Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (anId);
aSettings.SetEnableDepthTest (true);
aSettings.SetEnableDepthWrite(true);
aSettings.SetClearDepth      (true);
aSettings.SetPolygonOffset   (Graphic3d_PolygonOffset());
aViewer->SetZLayerSettings (anId, aSettings);

Z-Layer 功能的另一个应用是在显示远离世界中心(World Center)的对象时处理视觉精度问题。此类对象的关键问题是可视化数据是使用单精度浮点数(32 位)存储和操作的。单精度 32 位浮点数仅提供 6-9 位有效十进制数字的精度,而双精度 64 位数字提供 15-17 位有效十进制数字的精度,这对于大多数应用程序来说已经足够了。

当将对象移动到远离世界中心(World Center)的地方时,浮点数会稳定地消耗精度。相机眼睛(Eye)位置将前导十进制数字添加到整体对象变换中,由于浮点数性质,它会丢弃较小的数字。例如,大小为 0.0000123 的对象移动到位置 1000 的转换结果为 1000.0000123,它会溢出单精度浮点 - 考虑最乐观的 9 位有效数字的情况(但实际上不是这样),结果数值将为 1000.00001

这种不精确性会导致 3D 查看器中出现两种视觉伪影:

  • 整体每个顶点的对象失真。当在世界坐标系中定义了每个顶点位置时,就会发生这种情况。
  • 物体本身没有失真,但它在世界中的位置不稳定且不精确——物体在相机操作过程中会跳跃。当在局部坐标系中定义的顶点距离足够小以将精度保持在单个精度浮点数内时,会发生这种情况,但是应用于对象的局部变换(Local Transformation)会因单个精度浮点数而损坏。

如果不将整个呈现切换为双精度(对于每个顶点位置),就无法处理第一个问题。但是,可视化硬件使用单精度浮点数而不是双精度浮点数要快得多,因此在大多数情况下,这不是一个选项。然而,第二个问题可以通过应用特殊的渲染技巧来解决。

因此,要在 OCCT 中应用此功能,应用程序:

  • 为每个对象定义局部转换,以便将呈现数据拟合到单个精度浮点数中而不会失真。
  • 在空间上将世界划分为更小的区域/单元,单精度浮点数就足够了。这种单元的大小可能会有所不同,并且取决于应用程序所需的精度(例如,用户能够在应用程序中放大相机的程度)。
  • 为包含任何对象的每个空间单元定义一个 Z-Layer。
  • 根据单元的中心定义 Z-Layer 的局部原点(Local Origin)属性。
Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (anId);
aSettings.SetLocalOrigin (400.0, 0.0, 0.0);
  • 将可呈现的对象分配给最近的 Z-Layer。

请注意,图层(Layer)的局部原点(Local Origin)仅用于渲染 - 外部的所有内容仍将在世界坐标系(World Coordinate System)中定义,包括对象的局部变换(Local Transformation)和检测(Detection)结果。例如,在具有不同局部原点(Local Origins)的 Z-layers 之间移动呈现(presentation)时,对象将停留在同一位置 - 只有可视化质量会有所不同。

剪裁平面(Clipping planes)

定义自定义剪裁平面的功能对于某些任务可能非常有用。OCCT提供了这样的机会。

Graphic3d_ClipPlane 类提供裁剪平面的服务:它保存平面方程系数并提供其图形表示。要设置和获取平面方程系数,可以使用以下方法:

Graphic3d_ClipPlane::Graphic3d_ClipPlane (const gp_Pln& thePlane)
void Graphic3d_ClipPlane::SetEquation (const gp_Pln& thePlane)
Graphic3d_ClipPlane::Graphic3d_ClipPlane (const Equation& theEquation)
void Graphic3d_ClipPlane::SetEquation (const Equation& theEquation)
gp_Pln Graphic3d_ClipPlane::ToPlane() const

可以使用以下方法激活剪裁平面:

void Graphic3d_ClipPlane::SetOn (const Standard_Boolean theIsOn)

剪裁平面的数量是有限的。您可以通过 Graphic3d_GraphicDriver::InquireLimit() 方法检查限制值:

// get the limit of clipping planes for the current view
Standard_Integer aMaxClipPlanes = aView->Viewer()->Driver()->InquireLimit (Graphic3d_TypeOfLimit_MaxNbClipPlanes);

例如,让我们看看如何使用自定义参数创建新的剪裁平面并将其添加到视图或对象中:

// create a new clipping plane
Handle(Graphic3d_ClipPlane) aClipPlane = new Graphic3d_ClipPlane();
// change equation of the clipping plane
Standard_Real aCoeffA, aCoeffB, aCoeffC, aCoeffD = ...
aClipPlane->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
// set capping
aClipPlane->SetCapping (aCappingArg == "on");
// set the material with red color of clipping plane
Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
Quantity_Color aColor (1.0, 0.0, 0.0, Quantity_TOC_RGB);
aMat.SetAmbientColor (aColor);
aMat.SetDiffuseColor (aColor);
aClipPlane->SetCappingMaterial (aMat);
// set the texture of clipping plane
Handle(Graphic3d_Texture2Dmanual) aTexture = ...
aTexture->EnableModulate();
aTexture->EnableRepeat();
aClipPlane->SetCappingTexture (aTexture);
// add the clipping plane to an interactive object
Handle(AIS_InteractiveObject) aIObj = ...
aIObj->AddClipPlane (aClipPlane);
// or to the whole view
aView->AddClipPlane (aClipPlane);
// activate the clipping plane
aClipPlane->SetOn (Standard_True);
// update the view
aView->Update();

自动背面剔除(Automatic back face culling)

背面剔除可减少三角形的渲染数量(从而提高性能)并消除形状边界处的伪影。但是,此选项只能用于实体对象,其内部实际上从任何角度都是不可见的。默认情况下,自动背面剔除机制处于开启状态,该机制由 V3d_View::SetBackFacingModel() 控制。

StdPrs_ToolTriangulatedShape::IsClosed() 中应用了以下功能,用于在 ShadingAspect 中定义背面剔除:

  • 禁用自由封闭壳(free closed Shells)(不在实体内部)的剔除,因为自由壳的反向方向是有效的情况;
  • 能够剔除填充到复合体(compound)中的实体(Solids);
  • 忽略不完整三角剖分的实体(Solids)。

在以下情况下,背面剔除在 TKOpenGl 级别关闭:

  • 剪裁(clipping)/封盖(capping)平面有效;
  • 对于半透明物体;
  • 具有剖面线(hatching)呈现风格。

示例:创建 3D 场景

要创建 3D 图形对象并在屏幕中显示它们,请按照以下步骤操作:

  1. 创建属性(attributes)。
  2. 创建 3D 查看器(viewer)。
  3. 创建视图(view)。
  4. 创建交互上下文(interactive context)。
  5. 创建交互对象(interactive objects)。
  6. 在交互对象中创建基元(primitives)。
  7. 显示交互对象(interactive object)。

创建属性(attributes)

创建颜色。

Quantity_Color aBlack (Quantity_NOC_BLACK);
Quantity_Color aBlue (Quantity_NOC_MATRABLUE);
Quantity_Color aBrown (Quantity_NOC_BROWN4);
Quantity_Color aFirebrick (Quantity_NOC_FIREBRICK);
Quantity_Color aForest (Quantity_NOC_FORESTGREEN);
Quantity_Color aGray (Quantity_NOC_GRAY70);
Quantity_Color aMyColor (0.99, 0.65, 0.31, Quantity_TOC_RGB);
Quantity_Color aBeet (Quantity_NOC_BEET);
Quantity_Color aWhite (Quantity_NOC_WHITE);

创建线属性。

Handle(Graphic3d_AspectLine3d) anAspectBrown = new Graphic3d_AspectLine3d();
Handle(Graphic3d_AspectLine3d) anAspectBlue  = new Graphic3d_AspectLine3d();
Handle(Graphic3d_AspectLine3d) anAspectWhite = new Graphic3d_AspectLine3d();
anAspectBrown->SetColor (aBrown);
anAspectBlue ->SetColor (aBlue);
anAspectWhite->SetColor (aWhite);

创建标记(marker)属性。

Handle(Graphic3d_AspectMarker3d aFirebrickMarker = new Graphic3d_AspectMarker3d();
// marker attributes
aFirebrickMarker->SetColor (Firebrick);
aFirebrickMarker->SetScale (1.0f);
aFirebrickMarker->SetType (Aspect_TOM_BALL);
// or custom image
aFirebrickMarker->SetMarkerImage (theImage)

创建分面(facet)属性。

Handle(Graphic3d_AspectFillArea3d) aFaceAspect = new Graphic3d_AspectFillArea3d();
Graphic3d_MaterialAspect aBrassMaterial (Graphic3d_NameOfMaterial_Brass);
Graphic3d_MaterialAspect aGoldMaterial  (Graphic3d_NameOfMaterial_Gold);
aFaceAspect->SetInteriorStyle (Aspect_IS_SOLID_WIREFRAME);
aFaceAspect->SetInteriorColor (aMyColor);
aFaceAspect->SetDistinguishOn ();
aFaceAspect->SetFrontMaterial (aGoldMaterial);
aFaceAspect->SetBackMaterial  (aBrassMaterial);

创建文本属性。

Handle(Graphic3d_AspectText3d) aTextAspect = new Graphic3d_AspectText3d (aForest, Font_NOF_MONOSPACE, 1.0, 0.0);

创建 3D 查看器(Windows 示例)

// create a graphic driver
Handle(OpenGl_GraphicDriver) aGraphicDriver = new OpenGl_GraphicDriver (Handle(Aspect_DisplayConnection)());
// create a viewer
myViewer = new V3d_Viewer (aGraphicDriver);
// set parameters for V3d_Viewer
// defines default lights -
//   positional-light 0.3 0.0 0.0
//   directional-light V3d_XnegYposZpos
//   directional-light V3d_XnegYneg
//   ambient-light
a3DViewer->SetDefaultLights();
// activates all the lights defined in this viewer
a3DViewer->SetLightOn();
// set background color to black
a3DViewer->SetDefaultBackgroundColor (Quantity_NOC_BLACK);

创建 3D 视图(Windows 示例)

假定有效的 Windows 窗口已经可以通过 GetSafeHwnd() 方法访问(如 MFC 示例)。

Handle(WNT_Window) aWNTWindow = new WNT_Window (GetSafeHwnd());
myView = myViewer->CreateView();
myView->SetWindow (aWNTWindow);

创建交互上下文

myAISContext = new AIS_InteractiveContext (myViewer);

现在,您可以显示交互对象,例如 AIS_Shape

TopoDS_Shape aShape = BRepAPI_MakeBox (10, 20, 30).Solid();
Handle(AIS_Shape) anAISShape = new AIS_Shape (aShape);
myAISContext->Display (anAISShape, true);

创建你自己的交互对象

按照以下过程计算可呈现的对象:

请注意,有两种计算方法:一种用于标准表示,另一种用于退化(degenerated)表示,即在隐线消除(hidden line removal)和线框(wireframe)模式下。

让我们看一下计算方法的例子

void MyPresentableObject::Compute (const Handle(PrsMgr_PresentationManager)& thePrsManager,
                                   const Handle(Graphic3d_Structure)& thePrs,
                                   const Standard_Integer theMode)
(
  //...
)
void MyPresentableObject::Compute (const Handle(Prs3d_Projector)& theProjector,
                                   const Handle(Graphic3d_Structure)& thePrs)
(
  //...
)

在交互对象中创建基元

获取 Graphic3d_Structure 中使用的组。

Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();

更新组属性。

aGroup->SetGroupPrimitivesAspect (anAspectBlue);

aGroup 中创建两个三角形。

Standard_Integer aNbTria = 2;
Handle(Graphic3d_ArrayOfTriangles) aTriangles = new Graphic3d_ArrayOfTriangles (3 * aNbTria, 0, Graphic3d_ArrayFlags_VertexNormal);
for (Standard_Integer aTriIter = 1; aTriIter <= aNbTria; ++aTriIter)
{
  aTriangles->AddVertex (aTriIter * 5.,      0., 0., 1., 1., 1.);
  aTriangles->AddVertex (aTriIter * 5 + 5,   0., 0., 1., 1., 1.);
  aTriangles->AddVertex (aTriIter * 5 + 2.5, 5., 0., 1., 1., 1.);
}
aGroup->AddPrimitiveArray (aTriangles);
aGroup->SetGroupPrimitivesAspect (new Graphic3d_AspectFillArea3d());

使用 polyline 函数为组 aGroup 中的 thePrs 结构创建边界框。

Standard_Real Xm, Ym, Zm, XM, YM, ZM;
thePrs->MinMaxValues (Xm, Ym, Zm, XM, YM, ZM);
Handle(Graphic3d_ArrayOfPolylines) aPolylines = new Graphic3d_ArrayOfPolylines (16, 4);
aPolylines->AddBound (4);
aPolylines->AddVertex (Xm,  Ym, Zm);
aPolylines->AddVertex (Xm,  Ym, ZM);
aPolylines->AddVertex (Xm,  YM, ZM);
aPolylines->AddVertex (Xm,  YM, Zm);
aPolylines->AddBound (4);
aPolylines->AddVertex (Xm,  Ym, Zm);
aPolylines->AddVertex (XM,  Ym, Zm);
aPolylines->AddVertex (XM,  Ym, ZM);
aPolylines->AddVertex (XM,  YM, ZM);
aPolylines->AddBound (4);
aPolylines->AddVertex (XM,  YM, Zm);
aPolylines->AddVertex (XM,  Ym, Zm);
aPolylines->AddVertex (XM,  YM, Zm);
aPolylines->AddVertex (Xm,  YM, Zm);
aPolylines->AddBound (4);
aPolylines->AddVertex (Xm,  YM, ZM);
aPolylines->AddVertex (XM,  YM, ZM);
aPolylines->AddVertex (XM,  Ym, ZM);
aPolylines->AddVertex (Xm,  Ym, ZM);
aGroup->AddPrimitiveArray(aPolylines);
aGroup->SetGroupPrimitivesAspect (new Graphic3d_AspectLine3d());

在组 aGroup 中创建文本和标记。

static char* THE_TEXT[3] =
{
  "Application title",
  "My company",
  "My company address."
};
Handle(Graphic3d_ArrayOfPoints) aPtsArr = new Graphic3d_ArrayOfPoints (2, 1);
aPtsArr->AddVertex (-40.0, -40.0, -40.0);
aPtsArr->AddVertex (40.0, 40.0, 40.0);
aGroup->AddPrimitiveArray (aPtsArr);
aGroup->SetGroupPrimitivesAspect (new Graphic3d_AspectText3d());
Graphic3d_Vertex aMarker (0.0, 0.0, 0.0);
for (int i = 0; i <= 2; i++)
{
  aMarker.SetCoord (-(Standard_Real )i * 4 + 30,
                     (Standard_Real )i * 4,
                    -(Standard_Real )i * 4);
  aGroup->Text (THE_TEXT[i], Marker, 20.);
}

网格可视化服务(Mesh Visualization Services)

MeshVS (Mesh Visualization Service) 组件扩展了 Open CASCADE 技术的 3D 可视化功能。它提供了灵活的方法来显示网格以及相关的预处理器和后处理器数据。

从开发人员的角度来看,按照以下准则,可以很容易地将 MeshVS 组件集成到任何与网格相关的应用程序中:

  • MeshVS_DataSource 类派生一个数据源类。
  • 重新实现其虚方法,以便让 MeshVS 组件访问应用程序数据模型。这是工作中最重要的部分,因为可视化性能受数据源类的数据检索方法性能的影响。
  • 创建 MeshVS_Mesh 类的实例。
  • 创建数据源类的实例,并通过 SetDataSource() 方法将其传递给 MeshVS_Mesh 对象。
  • 创建一个或多个 MeshVS_PrsBuilder 派生类的对象(标准类,包含在 MeshVS 包中或自定义类)。
  • 每个 PrsBuilder 负责以指定为 PrsBuilder 构造函数参数的特定显示模式绘制 MeshVS_Mesh 呈现。MeshVS 类将显示模式视为位标志的组合(两个最低有效位用于对标准显示模式进行编码:线框、着色和收缩)。
  • 将这些对象传递给 MeshVS_Mesh::AddBuilder() 方法。MeshVS_Mesh 利用了改进的选择突出显示机制:在称为 highlighter 对象的帮助下,它突出显示了其选定的实体本身。您可以借助 AddBuilder() 方法的相应参数将其中一个 PrsBuilder 对象设置为 highlighter

MeshVS_Mesh 对象的视觉属性(如阴影颜色、收缩系数等)通过 MeshVS_Drawer 对象进行控制。它维护一个映射“属性 ID -->属性值”,并且可以使用任意数量的自定义属性轻松扩展。

在所有其他方面,MeshVS_Mesh 与派生自 AIS_InteractiveObject 的任何其他类非常相似,应相应地使用它(请参阅文档中对 AIS 包的描述)。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值