OpenCASCADE 显示与OpenGL的关系


@版权声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接https://www.jianshu.com/p/2e2cf9305aaf
如有问题, 可邮件([email protected])咨询。


关键字:OpenCASCADE、OpenGL、OCCT

OpenCASCADE中对象的显示完全是由OpenGL来实现的。那么OpenCASCADE是如何封装OpenGL的呢?这篇文章就带大家来捋一捋!

一. 从OpenCASCADE中AIS_Shape说起

OCCT中提供了一个可以显示的对象AIS_Shape。当需要显示一个AIS_Shape时,可以使用如下步骤:

Handle(AIS_Shape) hShape = MethodToGenerateAShape();生成要显示的AIS_Shape
Handle(AIS_InteractiveContext) hContext =MethodToGetAISContext();//获取显示上下文
hContext->Display(hShape,Standard_True);//Display进行显示

通过调用AIS_InteractiveContext的Display方法来进行对象的显示
那么一切就从这里开始吧!
如果有代码段,请注意代码中的加粗部分

1. AIS_InteractiveContext

通过AIS_InteractiveContext,你可以 在一个或者多个viewers中对图形对象进行选择和以及进行各种后续操作.

AIS_InteractiveContext继承关系及包含的部分成员变量如下:

class AIS_InteractiveContext : public Standard_Transient

protected:
Handle(SelectMgr_SelectionManager) mgrSelector;//选择对象管理器
Handle(PrsMgr_PresentationManager3d) myMainPM;//显示对象管理器
Handle(V3d_Viewer) myMainVwr;//主显示Viewer

下面是两个Diplay方法的说明

//! 外部调用方法 ,通过指定的显示模式来显示对象
void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIObj,
const Standard_Boolean theToUpdateViewer)
{
...
注:由于篇幅有限这里省略了与本文讲解无关的代码!
...
//下面调用Display的第二个重载方法
Display (theIObj, aDispMode, myIsAutoActivateSelMode ? aSelMode : -1,
theToUpdateViewer, theIObj->AcceptShapeDecomposition());

}

以上方法仅仅是调用了Display的另一个重载,如下:

void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIObj, const Standard_Integer theDispMode,const Standard_Integer theSelectionMode,const Standard_Boolean theToUpdateViewer,const Standard_Boolean theToAllowDecomposition,const AIS_DisplayStatus theDispStatus)
{
...
注:由于篇幅有限这里省略了与本文讲解无关的代码!
...
if (!myObjects.IsBound (theIObj))
{
Handle(AIS_GlobalStatus) aStatus = new AIS_GlobalStatus (AIS_DS_Displayed, theDispMode, theSelectionMode);
myObjects.Bind (theIObj, aStatus);
myMainVwr->StructureManager()->RegisterObject (theIObj);
//myMainPM 为 PrsMgr_PresentationManager3d
myMainPM->Display(theIObj, theDispMode);
...
if (theToUpdateViewer)
{
myMainVwr->Update();
}
}

可知,再经过AIS_InteractiveContext中的Dispaly方法进行各种判断处理后,最终调用的是 PrsMgr_PresentationManager3d 的Dispaly方法。

2. PrsMgr_PresentationManager3d

typedef PrsMgr_PresentationManager PrsMgr_PresentationManager3d;

根据宏定义可知: PrsMgr_PresentationManager3d 就是 PrsMgr_PresentationManager

3. PrsMgr_PresentationManager

PrsMgr_PresentationManager是一个处理3D图形显示的框架,用来管理图形显示以及更新
//! A framework to manage 3D displays, graphic entities and their updates.
//! Used in the AIS package (Application Interactive Services), to enable the advanced user to define the
//! default display mode of a new interactive object which extends the list of signatures and types.
//! Definition of new display types is handled by calling the presentation algorithms provided by the StdPrs package.

PrsMgr_PresentationManager继承关系及包含的部分成员变量如下:

class PrsMgr_PresentationManager : public Standard_Transient

protected:
Handle(Graphic3d_StructureManager) myStructureManager;//Structure管理器
Standard_Integer myImmediateModeOn;
PrsMgr_ListOfPresentations myImmediateList;
PrsMgr_ListOfPresentations myViewDependentImmediateList;

下面是PrsMgr_PresentationManager的Display方法

//! Displays the presentation of the object in the given Presentation manager with
//the given mode.
//! The mode should be enumerated by the object which inherits PresentableObject.
void PrsMgr_PresentationManager::Display (const Handle(PrsMgr_PresentableObject)& thePrsObj, const Standard_Integer theMode){ if (thePrsObj->HasOwnPresentations()) {
Handle(PrsMgr_Presentation) aPrs = Presentation (thePrsObj, theMode, Standard_True);if (aPrs->MustBeUpdated())
{
Update (thePrsObj, theMode);
}
if (myImmediateModeOn > 0)
{
//如果需要立即显示就将Presentateion添加到myImmediateList列表
AddToImmediateList (aPrs->Presentation());
}
else
{
aPrs->Display(); //这里调用PrsMgr_Presentation的Display
}
}
else
{
thePrsObj->Compute (this, Handle(Prs3d_Presentation)(), theMode);
}
for (PrsMgr_ListOfPresentableObjectsIter anIter (thePrsObj->Children()); anIter.More(); anIter.Next())
{
//这里遍历,进行所有需要显示的对象全部进行显示
Display (anIter.Value(), theMode);
}
}

PrsMgr_PresentationManager的Display方法里,通过不断循环最终调用Prs3d_Presentation的Display方法
下面来考察Prs3d_Presentation

4. Prs3d_Presentation **

Prs3d_Presentation表示一个可以进行显示、高亮以及删除的对象。一个显示对象将与一个指定的Viewr相关联。
Prs3d_Presentation Defines a presentation object which can be displayed, highlighted or erased.The presentation object stores the results of the presentation algorithms as defined in the StdPrs classes and the Prs3d classes inheriting Prs3d_Root.This presentation object is used to give display attributes defined at this level toApplicationInteractiveServices classes at the level above.A presentation object is attached to a given Viewer.

Prs3d_Presentation继承关系如下:

class Prs3d_Presentation : public Graphic3d_Structure

由于公有继承于Graphic3d_Structure。所以包含Graphic3d_Structure的所有非私有成员变量。该类重写的Graphic3d_Structure的各种Compute方法
当然Display()方法也是Graphic3d_Structure的

5. Graphic3d_Structure **

Graphic3d_Structure定义了一个图形对象。一个Graphic3d_Structure是可以被显示、高亮以及删除的。Graphic3d_Structure还可以与其他的Graphic3d_Structure关联。
This class allows the definition a graphic object.This graphic structure can be displayed,erased, or highlighted. This graphic structure can be connected with
another graphic structure.

Graphic3d_Structure继承关系及成员变量如下:

class Graphic3d_Structure : public Standard_Transient

protected:
Graphic3d_StructureManager* myStructureManager;//结构管理器
Graphic3d_TypeOfStructure myComputeVisual;//计算类型
Handle(Graphic3d_CStructure) myCStructure; //其实是OpenGL_Structure
Graphic3d_IndexedMapOfAddress myAncestors;
Graphic3d_IndexedMapOfAddress myDescendants;
Standard_Address myOwner;
Graphic3d_TypeOfStructure myVisual;//显示类型

Graphic3d_Structure中包含一个Graphic3d_CStructure的成员变量myCStructure。
这里的Graphic3d_CStructure就是OpenGL_Structure。OpenGL_Structure为Graphic3d_CStructure的子类。这里暂时不管,后面再谈!

下面出场的是Graphic3d_Structure的Display方法

Displays the structure in all the views of the visualiser.
void Graphic3d_Structure::Display()
{
if (IsDeleted()) return;
if (!myCStructure->stick)
{
myCStructure->stick = 1;
//这里调用Graphic3d_StructureManager的Display方法
myStructureManager->Display (this);
}if (myCStructure->visible != 1)
{
myCStructure->visible = 1;
myCStructure->OnVisibilityChanged();
}
}

6. Graphic3d_StructureManager

Graphic3d_StructureManager 允许你操作一组相关联的图形对象。并用一个统一的方式来操作它们。并且定义了一组全局的属性
This class allows the definition of a manager to which the graphic objects are associated.It allows them to be globally manipulated.It defines the global attributes.

Graphic3d_StructureManager的继承关系及部分成员变量如下:

class Graphic3d_StructureManager : public Standard_Transient

protected:
Aspect_GenId myViewGenId;
Graphic3d_MapOfStructure myDisplayedStructure;//一组已经显示的结构
Graphic3d_MapOfStructure myHighlightedStructure;//一组以及高亮显示的结构
Graphic3d_MapOfObject myRegisteredObjects;//被注册的对象。
//Graphic3d_GraphicDriver图形驱动其实是OpenGl_GraphicDriver
Handle(Graphic3d_GraphicDriver) myGraphicDriver;
Graphic3d_IndexedMapOfView myDefinedViews;//一组Graphic3d_CView
Standard_Boolean myDeviceLostFlag;

Graphic3d_StructureManager成员变量myGraphicDriver其实是OpenGl_GraphicDriver

还记得我们搭建MFC应用程序框架的时候怎么写的么?

  1. 在APP头文件中定义了一个成员变量
    Handle_Graphic3d_GraphicDriver myGraphicDriver;
  2. 在构造函数中实现
    Handle(Aspect_DisplayConnection) aDisplayConnection;
    myGraphicDriver = new OpenGl_GraphicDriver(aDisplayConnection);

下面是Graphic3d_StructureManager的Display方法介绍:

//Display the structure.
void Graphic3d_StructureManager::Display (const Handle(Graphic3d_Structure)& theStructure)
{
myDisplayedStructure.Add (theStructure);//将需要显示的对象添加到列表,然后遍历所有的View.调用Graphic3d_CView的Display来显示该结构
for (Graphic3d_IndexedMapOfView::Iterator aViewIt (myDefinedViews); aViewIt.More(); aViewIt.Next())
{
aViewIt.Value()->Display (theStructure);//Graphic3d_CView的Display来显示该结构
}
}

67可知,要显示一个Graphic3d_Structure,当然是,与该结构有关的所有的的view都要进行更新显示。所以Graphic3d_Structure的Display方法直接调用的是StructureManager的Display方法,在StructureManager的Display方法中,遍历所有的Graphic3d_CView并通知View进行结构的显示。

7. Graphic3d_IndexedMapOfView

typedef NCollection_IndexedMap Graphic3d_IndexedMapOfView

8. Graphic3d_CView

Graphic3d_CView只是作为基类使用,它的大部分方法都是纯虚方法。这些接口方法可以被具体的图形驱动类来重写。它提供的接口包括图形重绘、显示结构的管理以及渲染参数的设置。
Base class of a graphical view that carries out rendering process for a concrete implementation of graphical driver. Provides virtual interfaces for redrawing its
contents, management of displayed structures and render settings. The source code of the class itself implements functionality related to management of computed (HLR or "view-dependent") structures.

Graphic3d_CView继承关系及成员变量如下:

class Graphic3d_CView : public Graphic3d_DataStructureManager

protected:
Standard_Integer myId;
Graphic3d_RenderingParams myRenderParams;
Handle(Graphic3d_StructureManager) myStructureManager;//结构管理器
Graphic3d_SequenceOfStructure myStructsToCompute;//要进行计算的结构
Graphic3d_SequenceOfStructure myStructsComputed;//已经完成计算的结构
Graphic3d_MapOfStructure myStructsDisplayed;//已经显示的结构
Handle(Graphic3d_NMapOfTransient) myHiddenObjects;//隐藏的对象
Standard_Boolean myIsInComputedMode;
Standard_Boolean myIsActive;
Standard_Boolean myIsRemoved;
Graphic3d_TypeOfShadingModel myShadingModel;
Graphic3d_TypeOfVisualization myVisualization;

下面是Graphic3d_CView的Display方法介绍

void Graphic3d_CView::Display(const Handle(Graphic3d_Structure)& theStructure)
{
...
注:由于篇幅有限这里省略了与本文讲解无关的代码!
...
theStructure->CalculateBoundBox();//计算包围框
displayStructure (theStructure->CStructure(), theStructure->DisplayPriority());
Update (theStructure->GetZLayer());//更新zlayer
...
注:由于篇幅有限这里省略了与本文讲解无关的代码!
...
}

可知,在Display方法中实际调用的时displayStructure方法和Update方法

  1. //!Adds the structure to display lists of the view.
    virtual void displayStructure (const Handle(Graphic3d_CStructure)& theStructure,
    const Standard_Integer thePriority) = 0;
  1. void Graphic3d_CView::Update (const Graphic3d_ZLayerId theLayerId)
    {
    InvalidateZLayerBoundingBox (theLayerId);
    }

3 . //! Returns the bounding box of all structures displayed in the Z layer.
virtual void InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId) const = 0;

由1可知 DisplayStructure为一个纯虚方法。实际其实现在子类中实现。
由2和3 可知 Update方法也是调用了一个纯虚方法。在子类中实现。

OpenGl_View为Graphic3d_CView的子类。下面将正式进入OpenGL部分

二. OpenCascade中的OpenGL部分

OpenCascade的OpenGI包中提供的类封装了OpeGL的功能。
如:OpenGl_VertexBuffer封装了顶点缓存GL_ARRAY_BUFFER相关的操作
成员函数Create()封装了glGenBuffers()
成员函数Release()封装了glDeleteBuffers()
成员函数Bind()封装了glBindBuffer()
成员函数init ()封装了glBufferData()
成员函数subData()封装了glBufferSubData()
相信对Opengl的那些操作大家都不陌生吧。

好,话不多说,下面继续我们Display深挖

1. OpenGl_View ***

OpenGl_View类提供了OpenGL层面的显示相关的特性。特别是在OpenGl_View_Redraw.cxx文件中包括场景渲染drawBackgroundrenderScene,图形渲染displayStructure的实现。
OpenGl_View的继承以及成员函数如下:

class OpenGl_View : public Graphic3d_CView
protected:
OpenGl_GraphicDriver* myDriver;
Handle(OpenGl_Window) myWindow;
Handle(OpenGl_Workspace) myWorkspace;//OpenGl工作空间
Handle(Graphic3d_Camera) myCamera;
Handle(OpenGl_FrameBuffer) myFBO;
OpenGl_LayerList myZLayers; //!< main list of displayed structure, sorted by layers

下面是displayStructure 方法

//Adds the structure to display lists of the view.
void OpenGl_View::displayStructure (const Handle(Graphic3d_CStructure)& theStructure,const Standard_Integer thePriority)
{
const OpenGl_Structure* aStruct = reinterpret_cast (theStructure.operator->());
const Graphic3d_ZLayerId aZLayer = aStruct->ZLayer();
myZLayers.AddStructure (aStruct, aZLayer, thePriority);//仅仅只是添加到了列表
}

可以看出。这里仅仅是把我们的OpenGl_Structure添加到了ZLayers集合中并没有进行显示渲染
下面在来看看,下一个方法InvalidateZLayerBoundingBox

Returns the bounding box of all structures displayed in the Z layer.
Never fails. If Z layer does not exist nothing happens.
void OpenGl_View::InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId) const
{
if (myZLayers.LayerIDs().IsBound (theLayerId))
{
myZLayers.Layer (theLayerId).InvalidateBoundingBox();
}
else
{
const Standard_Integer aLayerMax = ZLayerMax();
for (Standard_Integer aLayerId = Graphic3d_ZLayerId_Default; aLayerId < aLayerMax; ++aLayerId)
{
if (myZLayers.LayerIDs().IsBound (aLayerId))
{
const OpenGl_Layer& aLayer = myZLayers.Layer (aLayerId);
if (aLayer.NbOfTransformPersistenceObjects() > 0)
{
aLayer.InvalidateBoundingBox();
}
}
}
}
}

OpenGl_Layer中可以发现
void InvalidateBoundingBox() const
{
myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
}

也就是说layer.InvalidateBoundingBox也只是标记了BoundingBox无效,后续渲染的时候在重新计算。而已!

那我们找了半天,AIS_InteractiveContex的Display方法中调用的PrsMgr_PresentationManager3d的Display()仅仅是将Structure的底层结构OpenGl_Structure添加到OpenGL_LayerList列表 并标记包围框在渲染的时候在进行重绘而已。

今天就到这吧,我先去哭一会!

其实Occt的比较高明的地方就在于,分层显示。根据不同的层可以设置不同的精度。或者其他渲染参数。所有这里都先将准备好的渲染数据分层进行存储,最终再由OpenGL进行渲染显示。

2. OpenGl_LayerList ***

表示一组OpeGI_Layer列表
OpenGl_LayerList的继承以及成员函数如下:

class OpenGl_View : public Graphic3d_CView
protected:
// number of structures temporary put to default layer
OpenGl_SequenceOfLayers myLayers;
OpenGl_LayerSeqIds myLayerIds;
//!< BVH tree builder for frustom culling
Handle(Select3D_BVHBuilder3d) myBVHBuilder;
//!< index of Graphic3d_ZLayerId_Default layer in myLayers sequence
Standard_Integer myDefaultLayerIndex;
Standard_Integer myNbPriorities;
Standard_Integer myNbStructures;
Standard_Integer myImmediateNbStructures; //!< number of structures within immediate layers

它提供了一个成员函数Render()用于渲染场景。当然也是遍历每一个OpenGl_Layer然后调用OpenGl_Layer的Render

for (; aLayerIter.More(); aLayerIter.Next())
{
const OpenGl_Layer& aLayer = aLayerIter.Value();
aLayer.Render (theWorkspace, aDefaultSettings);
})

3. OpenGl_Layer ***

OpenGl_Layer的继承以及成员函数如下:

class OpenGl_Layer : public Standard_Transient
private:
//Array of OpenGl_Structures by priority rendered in layer.
OpenGl_ArrayOfIndexedMapOfStructure myArray;
//! Layer setting flags.
Graphic3d_ZLayerSettings myLayerSettings;
//! Indexed map of always rendered structures.
mutable NCollection_IndexedMap myAlwaysRenderedMap;
//! Cached layer bounding box.
mutable Bnd_Box myBoundingBox[2];

它提供的成员函数有

// Render all structures.
void Render (const Handle(OpenGl_Workspace)& theWorkspace,
const OpenGl_GlobalLayerSettings& theDefaultSettings) const;

//! Iterates through the hierarchical list of existing structures and renders them all.
Standard_EXPORT void renderAll(const Handle(OpenGl_Workspace)& theWorkspace) const;

当然大部分都是OpenGl渲染方面的。感信息自己看源代码吧。

三. 弄清楚继承关系:

  1. Graphic3d_Structure 包含成员变量 Graphic3d_CStructure
    OpenGl_Structure 继承于 Graphic3d_CStructure

  2. V3d_View 包含成员变量 Graphic3d_CView 在V3d_View构造函数中同时创建
    OpenGI_View 继承于 Graphic3d_CView

  3. OpenGI_GraphicDriver 继承于 Graphic3d_GraphicDriver

Graphic3d_GraphicDriver由我们搭框架时候创建

Handle(Aspect_DisplayConnection) aDisplayConnection;
Handle(Graphic3d_GraphicDriver) myGraphicDriver = new OpenGl_GraphicDriver(aDisplayConnection);

V3d_Viewer由我们搭框架时候创建

Handle(V3d_Viewer) myViewer = new V3d_Viewer(aGraphicDriver);
Handle_V3d_View myView = myViewer->CreateView()
Handle(V3d_View) V3d_Viewer::CreateView ()
{
return new V3d_View(this, myDefaultTypeOfView);
}

3 . V3d_View 包含成员变量 Graphic3d_CView 在V3d_View构造函数中同时创建

new V3d_View()

Handle(Graphic3d_CView) myView;
myView = theViewer->Driver()->CreateView (theViewer->StructureManager());

Handle(Graphic3d_CView) OpenGl_GraphicDriver::CreateView (const Handle(Graphic3d_StructureManager)& theMgr)
{
Handle(OpenGl_View) aView = new OpenGl_View (theMgr, this, myCaps, &myStateCounter);
myMapOfView.Add (aView);
for (TColStd_SequenceOfInteger::Iterator aLayerIt (myLayerSeq); aLayerIt.More(); aLayerIt.Next())
{
const Graphic3d_ZLayerId aLayerID = aLayerIt.Value();
const Graphic3d_ZLayerSettings& aSettings = myMapOfZLayerSettings.Find (aLayerID);
aView->AddZLayer (aLayerID);
aView->SetZLayerSettings (aLayerID, aSettings); }
return aView;
}

当以上三步完成。OpenGI_View就被创建了。后面的渲染就交给OpenGL_View完成。

总结:
OpenCASCADE的OpenGI库封装了Opengl相关的渲染操作,它提供的生成及构建AIS_Shape的各种工具类都只是在为Opengl提供显示的数据。
在需要对AIS_Shape进行显示的时候,调用的Display仅仅是将AIS_Shape底层的数据结构OpenGl_Structure添加到层列表OpenGI_LayerList中,在后期需要渲染的时候再统一渲染。

后面将专门写一篇,介绍OpenCASCADE的OpenGI包。分析OpenCASCADE是如何准备opengl需要的数据的。希望大家多多支持!

你可能感兴趣的:(OpenCASCADE 显示与OpenGL的关系)