OSG採用包圍體層次(Bounding Volume Hierarchy, HVH)來實現場景圖形的管理。即是將一組物體完全封閉在一個簡單空間形體中,從而提高各種檢測的運算速度。OSG綜合使用包圍球和包圍盒。
包圍體層次的場景圖的組織結構爲樹,OSG通過樹來繪製模型。在OSG中存在場景樹和渲染樹兩顆樹。場景樹由Node組成,這些Node可能是矩陣變換、狀態切換或真正的可繪製對象,反映了場景的空間結構和對象的狀態。渲染樹是一顆一StateSet和RenderLeaf爲節點的樹。
在有的地方,組節點被稱爲枝節節點,葉節點被稱爲葉子節點。
場景採用一種自頂向下的、分層的樹狀數據結構來組織空間數據集,以提升渲染的效率。
OSG主要包含3大基本類節點——Node、Geode(Geometry Node,爲葉節點,即不會再有子節點,但可包含幾何體信息)、Group(組節點)。
Geode:葉節點。管理和繪製多個Drawable對象。這些可繪製對象可能是幾何形體、複雜模型、場景中的文字和圖片、噴薄而出的大量粒子,這些需要渲染的可繪製體可能是以某種位置和姿態固定在三維空間中、直接繪製到二維圖形窗口設備、自動轉向用戶所在方向的、形同廣告牌(Billboard)的一些特殊物體。
Group:組節點。最基本的功能是作爲場景樹結構的枝節存在,將子節點成組進行管理和調度。當一個Group節點的性質發生變化,其所有子節點也會隨之發生類似的變化。類似於搖晃一棵樹的枝條,其子分支、葉子和果實都會隨之晃動甚至掉落。主要分類爲:
(1)空間變換節點:改變自身在三維空間中的位置和姿態,進而影響子節點的空間位置變化。
(2)開關節點:管理類別信息的顯示、凍結或者隱藏。如隱藏圖像上所有河流、所有公路;再如分別控制國道省道的顯示與否。
(3)細節層次節點:在不影響渲染外觀的前提下,根據實際情況選擇一種更簡單的方式來表達要渲染的物體,減輕系統繪製場景的負擔。一般根據距離來決定顯示哪些細節。
(4)相機節點:從多視角觀察同一個場景。如正視、俯視、仰視。
(5)投影節點:類似投影儀,將子場景投影到二維平面上,從而可以方便地將所需要表達的內容呈現給用戶。
(6)渲染屬性節點:表達真實場景不可或缺的要素,光照、霧效果、透明效果、紋理貼圖等。OSG爲每個節點設置「渲染狀態集」的方式來管理渲染屬性,因此父節點的渲染屬性可以有選擇地集成到子節點上。
(7)覆蓋節點:以實例說明:電影院的人看電影,電影院是一個三維場景A;電影這個故事發生在另一個三維場景B中,因此可以稱爲將場景A覆蓋到電影院的熒幕對象上。
(8)遮擋裁剪節點:由於計算機硬件條件限制,大規模場景通常不能直接繪製,只有剔除掉用戶看不到的地方,如背面、視錐體、被遮擋等。
(9)動態調度節點:當將大量模型讀入內存時,計算機系統負擔較大,可能會因爲內存不足而程序出錯,甚至系統崩潰,此時需要一種動態調度的機制。對於該節點,當它的某些子節點對場景繪製長期沒有助益時可以將子節點自動卸載,釋放內存空間;也可以即時加載某些不再內存中的子節點,即動態對其場景子樹進行調度控制。
(10)關節節點:人體動作動畫,或者機械臂的旋轉移動。
(11)代理節點:只作爲另外一種尚未加載的節點的代理者而存在,被代理的對象會在適當的時候被加載到內存中;在此之前,代理者起到佔位和節省系統啓動時間的作用。
具體繼承關係如圖所示:
獲取某個節點對象並讀取它的屬性,以及對其執行指定用戶操作的過程。
向不同的節點元素施加用戶自定義的操作,將這些操作整合到一個對象中,同時避免這些操作可能造成的數據結構本身的變化,從而實現了一種更爲自由的編碼方式。
對於節點的訪問是從節點接受一個訪問器開始的,用戶執行某個節點的accept()函數,將一個具體的訪問器對象傳遞給節點。然後節點反過來執行訪問器的apply()函數,並將自身傳入訪問器。最後,在具體訪問器對象中重寫的apply()函數中,執行節點的具體訪問操作。
OSG中節點訪問器對於場景樹的訪問採用的是深度優先遍歷的形式:訪問節點直至末端的葉節點,再逐步返回到上一級尚未訪問的節點。
OSG中的節點主要使用回調來完成用戶臨時定義的、需要每幀執行的工作。包括更新回調和人機交互事件回調。前者在每幀系統遍歷到當前節點時都會被自動調用;後者爲操作鍵盤、鼠標、關閉窗口、改變窗口尺寸等人機交互事件觸發。
1、osg::Node類
Node() //默認構造函數 void dirtyBound() //提示更新節點的包圍體 const BoundingSphere &getBound() const //獲取節點的包圍體 BoundingSphere computeBound() const //虛函數,計算節點包圍體 const ParentList getParents() const //獲取節點的父節點列表 const Group *getParent(unsigned int i) const //獲取制定的父節點 unsigned int getNumParents() const //獲取父節點的數目 void addParent(Group *node) //爲當前節點追加一個父節點 void removeParent(Group *node) //刪除當前節點的某個父節點 void accept(NodeVisitor &nv) //接受一個訪問器 void ascend(NodeVisitor &nv) //虛函數。向上一級節點推進訪問器 void traverse(NodeVisitor &nv) //虛函數。向下一級節點推進訪問器 //例:獲取和操作節點的每一個父節點的方法 for (unsigned int i = 0; i<getNumParents(); ++i) { const osg::Group *parent = node.getParent(i); /*執行parent對象的操作*/ } void setUpdateCallback(NodeCallback *) //設置節點的更新回調 NodeCallback *getUpdateCallback() //獲取節點的更新回調 void setEventCallback(NodeCallback *) //設置節點的交互事件回調 NodeCallback *getEventCallback() //獲取節點的交互事件回調
2、osg::Geode類
Geode() //默認構造函數 bool addDrawable(Drawable *) //從葉節點追加一個可繪製體對象 boolremoveDrawable(Drawable *) //從葉節點刪除一個可繪製體對象 virtual bool removeDrawables(unsigned int i, unsigned int numToRemove)//從制定索引位置開始,刪除制定數目的可繪製體 bool replaceDrawable(Drawable *origDraw, Drawable *newDraw) //將當前節點中包含的一個可繪製體替換爲新的可繪製體 unsigned int getNumDrawables() const //獲取可繪製體的數目 Drawable *getDrawables(unsigned int i) //獲取一個指定位置的可繪製體 unsigned int getDrawableIndex(const Drawable *) const //獲取一個可繪製體在葉節點的索引位置 const DrawableList &getDrawableList() const //獲取可繪製體的列表 //例:在可繪製體drawable1和drawable2中加入一個葉節點,然後從葉節點中獲取並操作索引位置爲i的可繪製體 osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->addDrawable(drawable1); geode->addDrawable(drawable2); osg::Drawable *drawable = geode->getDrawable(i);
3、osg::Group類
Group() //默認構造函數 bool addChild(Node *child) //追加一個子節點 bool removeChild(Node *child) //刪除一個子節點 bool removeChildren(unsigned int pos, unsigned int numToRemove) //從指引索引位置開始,刪除制定數目的子節點 bool insertChild(unsigned int index, Node *child) //向指定索引位置插入一個子節點 bool replaceChild(Node *origChild, Node *newChild) //將當前節點中包含一個子節點替換爲新的子節點 unsigned int getNumChildren() const //獲取子節點的數目 Node *getChild(unsigned int i) //獲取一個指定位置的子節點 unsigned int getChildIndex(const Node *node) const //獲取一個子節點的索引位置
4、osg::NodeVisitor類
NodeVisitor(TraversalMode tm) //構造函數。傳入參數爲節點樹的遍歷方式:TRAVERSE_NODE僅當前節點;TRAVERSE_PARENTS向當前節點的父節點遍歷;TRAVERSE_ALL_CHILDREN向子節點遍歷 void traverse(Node &node) //向下一個需要訪問的節點推進 //虛函數。訪問各種類型的節點,並執行訪問器中自定義的節點操作 void apply(Node &node) void apply(Node &node) void apply(Node &node)
5、osg::NodeCallback類
NodeCallback() //默認構造函數 void operator()(Node *node, NodeVisitor *nv) //虛函數。當回調動作發生時,將會執行這一操作符的內容,並將節點和訪問器對象作爲參數傳入 void addNestedCallback(NodeCallback *) //添加一個臨近回調,其內容將在節點回調的執行過程中被依次調用 void removeNestedCallback(NodeCallback *) //移除一個臨近回調 void setNestedCallback(NodeCallback *) //直接設置一個臨近回調 NodeCallback *getNestedCallback(NodeCallback *) //直接獲取一個臨近回調
6、osg::Transform類
Transform() //默認構造函數 void setReferenceFrame(ReferenceFrame rf) //設置節點所用的參考座標系 ReferenceFrame getReferenceFrame() const //獲取節點所用的參考座標系 bool computerLocalToWorldMatrix(Matrix &matrix, NodeVisitor *nv) const //虛函數。計算從局部座標系到世界座標系的級聯矩陣,保存到matrix變量中 bool computerWorldToLocalMatrix(Matrix &matrix, NodeVisitor *nv) const //虛函數。計算從世界座標系到局部座標系的級聯矩陣,保存到matrix變量
7、osg::MatrixTransform類
MatrixTransform() //默認構造函數 void setMatrix(const Matrix &mat) //設置空間變換矩陣的內容 const Matrix &getMatrix() const //獲取空間變換矩陣的內容 void preMult(const Matrix &mat) //遞乘,比較類似於++a void postMult(const Matrix &mat) //遞乘,比較類似於a++ const Matrix &getInverseMatrix() const //得到逆矩陣
8、osg::PositionAttitudeTransform類
PositionAttitudeTransform() //默認構造函數 void setPosition(const VEC3D &) //設置空間中平移的距離 const Vec3d &getPosition() const //獲取空間中平移的距離 void setAttitude(const Quat &) //設置空間中旋轉的四元數 const Quat &getAttitude() const //獲取空間中旋轉的四元數 void setScale(const Vec3d &) //設置空間縮放的倍數 const Vec3d& getScale() const //獲取空間縮放的倍數 void setPivotPoint(const Vec3d&) //設置空間旋轉與縮放的軸心位置 const Vec3d& getPivotPoint() const //獲取空間旋轉與縮放的軸心位置
9、osg::Switch類
Switch() //默認構造函數 bool addChild(Node *child, bool) //添加一個子節點,同時設置其開關值 void setValue(unsigned int pos, bool) //設置指定索引pos位置子節點的開關值 bool getValue(unsigned int pos) const //獲取指定索引pos位置子節點的開關值 void setNewChildDefaultValue(bool value) //設置新加節點的初始值 bool getNewChildDefaultValue() const //得到新加節點的初始值 void setChildValue(const Node *child, bool value) //設置child的值 bool getChildValue(const Node *child) const //得到child的值 bool setAllChildrenOff() //設置所有子節點不顯示 bool setAllChildrenOn() //設置所有子節點顯示 bool setSingleChildOn(unsigned int pos) //設置索引pos單個節點顯示
10、osg::LOD類
LOD() //默認構造函數 bool addChild(Node *child, float min, float max) //添加一個子節點,並設置其對應的觀察範圍 void setRange(unsigned int childNo, float min, float max) //設置指定位置的子節點對應的觀察範圍 float getMinRange(unsigned int childNo) const //獲取某個子節點對應的觀察最小值 float getMaxRange(unsigned int childNo) const //獲取某個子節點對應的觀察最大值 const RangeList &getRangeList() const //獲取所有子節點觀察範圍的列表