1. 程式人生 > >OSG學習:OSG組成(二)——場景樹

OSG學習:OSG組成(二)——場景樹

以下內容來自: 

1、《OpenSceneGraph三維渲染引擎程式設計指南》肖鵬 劉更代 徐明亮 清華大學出版社; 

2、《OpenSceneGraph3.0三維視景模擬技術開發詳解》國防工業出版社

3、《OpenSceneGraph三維渲染引擎設計與實踐》王銳 錢學雷 清華大學出版社

4、自己的總結,包括圖。

一 概述

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 //獲取所有子節點觀察範圍的列表