OpenCASCADE 顯示與OpenGL的關(guān)系


@版權(quán)聲明:本文版權(quán)歸作者所有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出,
本文鏈接http://www.itdecent.cn/p/2e2cf9305aaf
如有問題, 可郵件(yumxuanyi@qq.com)咨詢。


關(guān)鍵字:OpenCASCADE、OpenGL、OCCT

OpenCASCADE中對象的顯示完全是由OpenGL來實現(xiàn)的。那么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進行顯示

通過調(diào)用AIS_InteractiveContext的Display方法來進行對象的顯示。
那么一切就從這里開始吧!
如果有代碼段,請注意代碼中的加粗部分

1. AIS_InteractiveContext

通過AIS_InteractiveContext,你可以 在一個或者多個viewers中對圖形對象進行選擇和以及進行各種后續(xù)操作.

AIS_InteractiveContext繼承關(guān)系及包含的部分成員變量如下:

class AIS_InteractiveContext : public Standard_Transient

protected:
Handle(SelectMgr_SelectionManager) mgrSelector;//選擇對象管理器
Handle(PrsMgr_PresentationManager3d) myMainPM;//顯示對象管理器
Handle(V3d_Viewer) myMainVwr;//主顯示Viewer

下面是兩個Diplay方法的說明

//! 外部調(diào)用方法 ,通過指定的顯示模式來顯示對象
void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIObj,
const Standard_Boolean theToUpdateViewer)
{
...
注:由于篇幅有限這里省略了與本文講解無關(guān)的代碼!
...
//下面調(diào)用Display的第二個重載方法
Display (theIObj, aDispMode, myIsAutoActivateSelMode ? aSelMode : -1,
theToUpdateViewer, theIObj->AcceptShapeDecomposition());

}

以上方法僅僅是調(diào)用了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)
{
...
注:由于篇幅有限這里省略了與本文講解無關(guān)的代碼!
...
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();
}
}

可知,再經(jīng)過AIS_InteractiveContext中的Dispaly方法進行各種判斷處理后,最終調(diào)用的是 PrsMgr_PresentationManager3d 的Dispaly方法。

2. PrsMgr_PresentationManager3d

typedef PrsMgr_PresentationManager PrsMgr_PresentationManager3d;

根據(jù)宏定義可知: 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繼承關(guān)系及包含的部分成員變量如下:

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(); //這里調(diào)用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方法里,通過不斷循環(huán)最終調(diào)用Prs3d_Presentation的Display方法
下面來考察Prs3d_Presentation

4. Prs3d_Presentation **

Prs3d_Presentation表示一個可以進行顯示、高亮以及刪除的對象。一個顯示對象將與一個指定的Viewr相關(guān)聯(lián)。
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繼承關(guān)系如下:

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關(guān)聯(lián)。
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繼承關(guān)系及成員變量如下:

class Graphic3d_Structure : public Standard_Transient

protected:
Graphic3d_StructureManager* myStructureManager;//結(jié)構(gòu)管理器
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 <me> in all the views of the visualiser.
void Graphic3d_Structure::Display()
{
if (IsDeleted()) return;
if (!myCStructure->stick)
{
myCStructure->stick = 1;
//這里調(diào)用Graphic3d_StructureManager的Display方法
myStructureManager->Display (this);
}if (myCStructure->visible != 1)
{
myCStructure->visible = 1;
myCStructure->OnVisibilityChanged();
}
}

6. Graphic3d_StructureManager

Graphic3d_StructureManager 允許你操作一組相關(guān)聯(lián)的圖形對象。并用一個統(tǒng)一的方式來操作它們。并且定義了一組全局的屬性
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的繼承關(guān)系及部分成員變量如下:

class Graphic3d_StructureManager : public Standard_Transient

protected:
Aspect_GenId myViewGenId;
Graphic3d_MapOfStructure myDisplayedStructure;//一組已經(jīng)顯示的結(jié)構(gòu)
Graphic3d_MapOfStructure myHighlightedStructure;//一組以及高亮顯示的結(jié)構(gòu)
Graphic3d_MapOfObject myRegisteredObjects;//被注冊的對象。
//Graphic3d_GraphicDriver圖形驅(qū)動其實是OpenGl_GraphicDriver
Handle(Graphic3d_GraphicDriver) myGraphicDriver;
Graphic3d_IndexedMapOfView myDefinedViews;//一組Graphic3d_CView
Standard_Boolean myDeviceLostFlag;

Graphic3d_StructureManager成員變量myGraphicDriver其實是OpenGl_GraphicDriver

還記得我們搭建MFC應(yīng)用程序框架的時候怎么寫的么?

  1. 在APP頭文件中定義了一個成員變量
    Handle_Graphic3d_GraphicDriver myGraphicDriver;
  2. 在構(gòu)造函數(shù)中實現(xiàn)
    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.調(diào)用Graphic3d_CView的Display來顯示該結(jié)構(gòu)
for (Graphic3d_IndexedMapOfView::Iterator aViewIt (myDefinedViews); aViewIt.More(); aViewIt.Next())
{
aViewIt.Value()->Display (theStructure);//Graphic3d_CView的Display來顯示該結(jié)構(gòu)
}
}

67可知,要顯示一個Graphic3d_Structure,當然是,與該結(jié)構(gòu)有關(guān)的所有的的view都要進行更新顯示。所以Graphic3d_Structure的Display方法直接調(diào)用的是StructureManager的Display方法,在StructureManager的Display方法中,遍歷所有的Graphic3d_CView并通知View進行結(jié)構(gòu)的顯示。

7. Graphic3d_IndexedMapOfView

typedef NCollection_IndexedMap<Graphic3d_CView*> Graphic3d_IndexedMapOfView

8. Graphic3d_CView

Graphic3d_CView只是作為基類使用,它的大部分方法都是純虛方法。這些接口方法可以被具體的圖形驅(qū)動類來重寫。它提供的接口包括圖形重繪、顯示結(jié)構(gòu)的管理以及渲染參數(shù)的設(shè)置。
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繼承關(guān)系及成員變量如下:

class Graphic3d_CView : public Graphic3d_DataStructureManager

protected:
Standard_Integer myId;
Graphic3d_RenderingParams myRenderParams;
Handle(Graphic3d_StructureManager) myStructureManager;//結(jié)構(gòu)管理器
Graphic3d_SequenceOfStructure myStructsToCompute;//要進行計算的結(jié)構(gòu)
Graphic3d_SequenceOfStructure myStructsComputed;//已經(jīng)完成計算的結(jié)構(gòu)
Graphic3d_MapOfStructure myStructsDisplayed;//已經(jīng)顯示的結(jié)構(gòu)
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)
{
...
注:由于篇幅有限這里省略了與本文講解無關(guān)的代碼!
...
theStructure->CalculateBoundBox();//計算包圍框
displayStructure (theStructure->CStructure(), theStructure->DisplayPriority());
Update (theStructure->GetZLayer());//更新zlayer
...
注:由于篇幅有限這里省略了與本文講解無關(guān)的代碼!
...
}

可知,在Display方法中實際調(diào)用的時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為一個純虛方法。實際其實現(xiàn)在子類中實現(xiàn)。
由2和3 可知 Update方法也是調(diào)用了一個純虛方法。在子類中實現(xiàn)。

OpenGl_View為Graphic3d_CView的子類。下面將正式進入OpenGL部分

二. OpenCascade中的OpenGL部分

OpenCascade的OpenGI包中提供的類封裝了OpeGL的功能。
如:OpenGl_VertexBuffer封裝了頂點緩存GL_ARRAY_BUFFER相關(guān)的操作
成員函數(shù)Create()封裝了glGenBuffers()
成員函數(shù)Release()封裝了glDeleteBuffers()
成員函數(shù)Bind()封裝了glBindBuffer()
成員函數(shù)init ()封裝了glBufferData()
成員函數(shù)subData()封裝了glBufferSubData()
相信對Opengl的那些操作大家都不陌生吧。

好,話不多說,下面繼續(xù)我們Display深挖

1. OpenGl_View ***

OpenGl_View類提供了OpenGL層面的顯示相關(guān)的特性。特別是在OpenGl_View_Redraw.cxx文件中包括場景渲染drawBackground 、renderScene,圖形渲染displayStructure的實現(xiàn)。
OpenGl_View的繼承以及成員函數(shù)如下:

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<const OpenGl_Structure*> (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中可以發(fā)現(xiàn)
void InvalidateBoundingBox() const
{
myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
}

也就是說layer.InvalidateBoundingBox也只是標記了BoundingBox無效,后續(xù)渲染的時候在重新計算。而已!

那我們找了半天,AIS_InteractiveContex的Display方法中調(diào)用的PrsMgr_PresentationManager3d的Display()僅僅是將Structure的底層結(jié)構(gòu)OpenGl_Structure添加到OpenGL_LayerList列表 并標記包圍框在渲染的時候在進行重繪而已。

今天就到這吧,我先去哭一會!

其實Occt的比較高明的地方就在于,分層顯示。根據(jù)不同的層可以設(shè)置不同的精度?;蛘咂渌秩緟?shù)。所有這里都先將準備好的渲染數(shù)據(jù)分層進行存儲,最終再由OpenGL進行渲染顯示。

2. OpenGl_LayerList ***

表示一組OpeGI_Layer列表
OpenGl_LayerList的繼承以及成員函數(shù)如下:

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

它提供了一個成員函數(shù)Render()用于渲染場景。當然也是遍歷每一個OpenGl_Layer然后調(diào)用OpenGl_Layer的Render

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

3. OpenGl_Layer ***

OpenGl_Layer的繼承以及成員函數(shù)如下:

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<const OpenGl_Structure*> myAlwaysRenderedMap;
//! Cached layer bounding box.
mutable Bnd_Box myBoundingBox[2];

它提供的成員函數(shù)有

// 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渲染方面的。感信息自己看源代碼吧。

三. 弄清楚繼承關(guān)系:

  1. Graphic3d_Structure 包含成員變量 Graphic3d_CStructure
    OpenGl_Structure 繼承于 Graphic3d_CStructure

  2. V3d_View 包含成員變量 Graphic3d_CView 在V3d_View構(gòu)造函數(shù)中同時創(chuàng)建
    OpenGI_View 繼承于 Graphic3d_CView

  3. OpenGI_GraphicDriver 繼承于 Graphic3d_GraphicDriver

Graphic3d_GraphicDriver由我們搭框架時候創(chuàng)建

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

V3d_Viewer由我們搭框架時候創(chuàng)建

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構(gòu)造函數(shù)中同時創(chuàng)建

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就被創(chuàng)建了。后面的渲染就交給OpenGL_View完成。

總結(jié):
OpenCASCADE的OpenGI庫封裝了Opengl相關(guān)的渲染操作,它提供的生成及構(gòu)建AIS_Shape的各種工具類都只是在為Opengl提供顯示的數(shù)據(jù)。
在需要對AIS_Shape進行顯示的時候,調(diào)用的Display僅僅是將AIS_Shape底層的數(shù)據(jù)結(jié)構(gòu)OpenGl_Structure添加到層列表OpenGI_LayerList中,在后期需要渲染的時候再統(tǒng)一渲染。

后面將專門寫一篇,介紹OpenCASCADE的OpenGI包。分析OpenCASCADE是如何準備opengl需要的數(shù)據(jù)的。希望大家多多支持!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容