OSG总结
在用戶(hù)程序中使用osg
?
一.渲染
Osg開(kāi)放了所有的功能模塊。因此用戶(hù)程序完全可以使用最底層的osg功能來(lái)執(zhí)行渲染操作。假設(shè)用戶(hù)希望能夠完全自主的控制場(chǎng)景圖形的渲染,那么也可以按照下面的步驟編寫(xiě)應(yīng)用程序的代碼:
1.?????? 設(shè)計(jì)自己的視角管理代碼:以改變OpenGL的模型視圖矩陣。
2.?????? 創(chuàng)建用戶(hù)窗口和OpenGL上下文,并將他們激活。如果有需要的話(huà),用戶(hù)也可以自行編寫(xiě)管理多窗口和多個(gè)設(shè)備上下文的代碼。
3.?????? 如果應(yīng)用程序需要使用分頁(yè)數(shù)據(jù)庫(kù),那么可以使用osgDB::DatabasePager類(lèi)
4.?????? 可以將osgUtil::UpdateVisitor,osgUtil::CullVisitor,osgUtil::RenderStage對(duì)象實(shí)例化,以實(shí)現(xiàn)場(chǎng)景的更新,挑選和繪制遍歷。如果用戶(hù)希望獲得更多的控制權(quán),則可以自己編寫(xiě)類(lèi)來(lái)實(shí)現(xiàn)以上遍歷的特性。
5.?????? 編寫(xiě)主循環(huán)代碼來(lái)處理操作系統(tǒng)返回的事件。并且調(diào)用自己的視角觀(guān)察代碼來(lái)更新模型視圖矩陣。
6.?????? 在渲染一幀之前先要調(diào)用glClear()。渲染時(shí)要依次執(zhí)行場(chǎng)景更新,挑選和繪制遍歷,最后交換緩存數(shù)據(jù)。
7.?????? 如果用戶(hù)程序或者運(yùn)行改程序的軟﹑硬件平臺(tái)需要立體化渲染(stereo rendering)或者多通道渲染(multipipe rendering)功能的支持,則可以自行編寫(xiě)額外的代碼。
8.?????? 最后請(qǐng)依照平臺(tái)無(wú)關(guān)性的要求來(lái)編寫(xiě)所有的代碼,這樣你的代碼才可以在所有的目標(biāo)平臺(tái)上運(yùn)行通過(guò)。
?
用戶(hù)使用osg時(shí),往往可以利用以下這些工具和庫(kù)來(lái)簡(jiǎn)化開(kāi)發(fā)的過(guò)程:
1.?????? osgUtil::SceneView:這個(gè)類(lèi)封裝了更新,挑選,和繪制遍歷,但是并不啟用DatabasePager。有一部分應(yīng)用程序會(huì)使用SceneView作為osg渲染的主接口。
2.?????? Producer和osgProducer—Producer是一個(gè)外部的攝像機(jī)庫(kù),可以支持多通道渲染。osgProducer是一個(gè)集成了Producer和osg的應(yīng)用庫(kù)。Producer有相當(dāng)多的用戶(hù),目前有一部分的osg程序是基于osgProducer和Producer開(kāi)發(fā)的。
?
Osg2.0版本核心添加了一個(gè)新的庫(kù)成員—osgViewer。osgViewer包含了一系列的用于控制視口顯示的相關(guān)的類(lèi),并封裝了大量用戶(hù)常用的功能函數(shù),例如顯示管理,事件響應(yīng),場(chǎng)景渲染等。這個(gè)庫(kù)使用osg::Camera類(lèi)來(lái)管理OpenGL的模型視圖矩陣。與SceneView類(lèi)不同,osgViewer的視口類(lèi)提供了對(duì)DatabasePager的全部支持。osgViewer還可以針對(duì)同一個(gè)場(chǎng)景圖形,提供并通過(guò)多個(gè)獨(dú)立的視口顯示該場(chǎng)景。
?
?? 3.1.1 Viewer類(lèi)
?
?? 改變視口:
?? Viewer在其內(nèi)部創(chuàng)建了一個(gè)osg::Camera攝像機(jī)對(duì)象來(lái)管理osg的模型—視圖矩陣。用戶(hù)可以通過(guò)以下的兩個(gè)方法來(lái)控制Camera對(duì)象。
?? ①將一個(gè)攝像機(jī)控制器對(duì)象關(guān)聯(lián)到Viewer中。如果你的程序不需要這么做,那么Viewer.run()將自動(dòng)創(chuàng)建一個(gè)osgGA::TrackballManipulator對(duì)象來(lái)控制攝像機(jī)的工作。osgGA庫(kù)定義了一些常用的控制器類(lèi)。用戶(hù)可以調(diào)用Viewer::setCameraManipulator來(lái)指定一個(gè)期望的控制器。
②設(shè)置Camera對(duì)象的投影矩陣和觀(guān)察矩陣為自定義的矩陣值。這樣也可以保證用戶(hù)程序能夠完全控制視口的瀏覽動(dòng)作。
osgViewer::setViewMatrix()方法來(lái)設(shè)置視口矩陣。參數(shù)是一個(gè)osg::Matrix矩陣,
osgViewer::setViewMatrixAsLookat():參數(shù)和gluLookAt類(lèi)似,三個(gè)向量:eye,center,up。
?
設(shè)置清屏顏色:
Camera::setClearColor()用來(lái)設(shè)置清屏顏色,缺省情況下會(huì)清除深度和顏色緩存,可以使用Camera::setClearMask(GL_CLOLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)來(lái)設(shè)置清除屬性。
?
3.1.2????????? SimpleViewer 和 CompositeViewer
?? osgViewer::SimpleViewer類(lèi)不會(huì)主動(dòng)的創(chuàng)建窗口或者設(shè)備上下文,它需要依賴(lài)用戶(hù)程序來(lái)創(chuàng)建窗口、上下文,并將其激活為當(dāng)前設(shè)備,如果操作正確的話(huà),SimpleViewer::frame()將會(huì)在用戶(hù)給定的窗口中渲染。
?? osgViewer::CompositeViewer:Viewer類(lèi)只能在一個(gè)場(chǎng)景中添加一個(gè)視口,而CompositeViewer類(lèi)可以支持一個(gè)或多個(gè)場(chǎng)景的多個(gè)視口顯示,并允許用戶(hù)程序指定其渲染順序。CompositeViewer還支持渲染到紋理(RTT)的操作,即,允許用戶(hù)程序?qū)⒁粋€(gè)視口中渲染的圖像作為另一個(gè)視口的紋理貼圖。
?
二.動(dòng)態(tài)更改
Osg允許用戶(hù)動(dòng)態(tài)的修改場(chǎng)景圖形并因而改變每一幀的顯示。用戶(hù)可以更改幾何數(shù)據(jù),渲染狀態(tài)參數(shù),Switch節(jié)點(diǎn)設(shè)置,以及任何場(chǎng)景圖形的結(jié)構(gòu)。OsgViewer庫(kù)支持多線(xiàn)程模式,每一個(gè)線(xiàn)程均獨(dú)立的運(yùn)行挑選及繪制遍歷,但osg并沒(méi)有為了線(xiàn)程的安全性增設(shè)內(nèi)存鎖,而是要求用戶(hù)程序只可在挑選及繪制遍歷的時(shí)域之外修改場(chǎng)景圖形。
?
確保用戶(hù)的修改不會(huì)與挑選及繪制線(xiàn)程發(fā)生沖突,一個(gè)簡(jiǎn)單的方案是,在Viewer::frame()的調(diào)用之外進(jìn)行場(chǎng)景圖形的修改,這需要在主渲染循環(huán)中添加額外的代碼。但如果用戶(hù)希望自己的程序更加整潔及規(guī)范的話(huà),可以選擇在更新遍歷中進(jìn)行場(chǎng)景的修改操作。
?
一些與場(chǎng)景圖形動(dòng)態(tài)更改相關(guān)的基本技術(shù):
1.?????? 處于性能優(yōu)化和線(xiàn)程安全性的考慮,用戶(hù)需要通知osg,場(chǎng)景圖形的哪些部分是可能要進(jìn)行修改的。用戶(hù)可以通過(guò)設(shè)置Object對(duì)象(Node,Drawable,StateSet等)的數(shù)據(jù)變度(data variance)屬性來(lái)完成這一工作。
2.?????? osh允許用戶(hù)為Node和Drawable設(shè)置回調(diào)(callback)。Osg將在特定遍歷中執(zhí)行這些回調(diào),
3.?????? 用戶(hù)程序有時(shí)不能預(yù)知場(chǎng)景圖形的哪一部分需要修改。這是需要搜索整個(gè)場(chǎng)景圖形來(lái)查找特定的節(jié)點(diǎn),或者由用戶(hù)使用鼠標(biāo)等輸入設(shè)備來(lái)選擇一個(gè)節(jié)點(diǎn)。
?
3.2.1??????? 數(shù)據(jù)邊度
? OsgViewer支持的多線(xiàn)程模型允許主循環(huán)不必等到繪制遍歷結(jié)束就可以繼續(xù)運(yùn)行,也就是Viewer::frame()方法在繪制遍歷仍未結(jié)束的時(shí)候就可以返回。換句話(huà)說(shuō),上一幀的繪制遍歷可以與下一幀的更新遍歷產(chǎn)生重疊。Osg提供了osg::object::DataVariance()方法解決繪制遍歷與多線(xiàn)程的更新操作的沖突。(Frame():Render a complete new frame)。用于處理繪制遍歷與其他遍歷的同步性。
?
3.2.2????????? 回調(diào)
Osg允許用戶(hù)設(shè)置Node和Drawable對(duì)象的回調(diào)類(lèi)。Node可以在執(zhí)行更新和挑選時(shí)進(jìn)行回調(diào),Drawable可以在挑選和繪制遍歷時(shí)進(jìn)行回調(diào)。
?
使用NodeCallback,用戶(hù)程序所需要執(zhí)行的步驟:
1.?????? 從NodeCallback繼承一個(gè)新的類(lèi)。
2.?????? 重載NodeCallback::operator()方法,實(shí)現(xiàn)場(chǎng)景圖形的動(dòng)態(tài)更改。
3.?????? 實(shí)例化繼承而來(lái)的類(lèi),然后使用Node::setUpdateCallback()方法關(guān)聯(lián)到將要修改的Node。
NodeCallback::operator()兩參數(shù):第一個(gè)是回調(diào)類(lèi)所關(guān)聯(lián)的Node節(jié)點(diǎn)地址,第二個(gè)參數(shù)是osg::NodeVisitor對(duì)象的地址。
?
NodeVisitor::traverse():這個(gè)方法允許osg訪(fǎng)問(wèn)其他的節(jié)點(diǎn)并執(zhí)行其回調(diào)。
?
3.2.3????????? NodeVisitor類(lèi)
這是osg對(duì)于訪(fǎng)問(wèn)器(visitor)設(shè)計(jì)思想的實(shí)現(xiàn)。從本質(zhì)上說(shuō),NodeVisitor類(lèi)遍歷了一個(gè)場(chǎng)景圖形并為每一個(gè)被訪(fǎng)問(wèn)節(jié)點(diǎn)調(diào)用特定的函數(shù)。這一簡(jiǎn)單的技術(shù)卻是許多osg操作的基類(lèi),如osgUtil::Optimizer,osgUtil的幾何體處理類(lèi)。Osg使用osgUtil::UpdateVisitor類(lèi)(繼承自NodeVisitor)來(lái)實(shí)現(xiàn)更新遍歷。
NodeVisitor是一個(gè)基類(lèi),用戶(hù)程序無(wú)法直接將其實(shí)例化。但用戶(hù)程序可以使用osg提供的任何NodeVisitor派生類(lèi),也可以自己編寫(xiě)繼承自NodeVisitor類(lèi)的代碼。NodeVisitor包含了一些經(jīng)過(guò)重載的apply()方法,其輸入?yún)?shù)涵蓋了大部分osg的節(jié)點(diǎn)類(lèi)型。當(dāng)一個(gè)NodeVisitor對(duì)象遍歷整個(gè)場(chǎng)景圖形時(shí),它將會(huì)為每個(gè)被訪(fǎng)問(wèn)的節(jié)點(diǎn)調(diào)用其相應(yīng)的apply()方法。
?
使用特定的名稱(chēng)來(lái)搜索節(jié)點(diǎn)也是一種簡(jiǎn)單而實(shí)用的操作。
?
允許NodeVisitor遍歷:
缺省情況下,NodeVisitor類(lèi)禁止執(zhí)行遍歷。因此在你的派生類(lèi)中,需要使用枚舉量NodeVisitor::TRAVERSE_ALL_CHILDREN來(lái)初始化基類(lèi),以允許執(zhí)行遍歷,否則osg將不會(huì)調(diào)用apply()方法。
?
如果要使用NodeVisitor來(lái)遍歷整個(gè)場(chǎng)景圖形,可以將NodeVisitor作為Node::accept()的輸入?yún)?shù)傳遞。你可以在任何一個(gè)節(jié)點(diǎn)上調(diào)用accept(),NodeVisitor將從那個(gè)節(jié)點(diǎn)開(kāi)始遍歷整個(gè)場(chǎng)景圖形,如果要搜索整個(gè)場(chǎng)景圖形的話(huà),可以從根節(jié)點(diǎn)開(kāi)始調(diào)用accept()。
?
3.2.4????????? 用戶(hù)選擇
從本質(zhì)上講,osg程序通過(guò)兩個(gè)步驟來(lái)實(shí)現(xiàn)用戶(hù)選擇:
1.?????? 接受鼠標(biāo)事件osgGA提供了允許程序接受鼠標(biāo)事件的事件類(lèi),它具備設(shè)備平臺(tái)無(wú)關(guān)特性。
2.?????? 判斷場(chǎng)景圖形的哪個(gè)部分被鼠標(biāo)光標(biāo)覆蓋。osgUtil提供了一種相交集類(lèi)(Intersection),可以在鼠標(biāo)xy坐標(biāo)的周?chē)鷦?chuàng)建包圍盒,并判段包圍盒與場(chǎng)景圖形的相交情況,osgUtil將按照由前至后的順序返回與包圍盒相交的節(jié)點(diǎn)列表。
?
?
捕捉鼠標(biāo)事件
osgGA::TrackballManipulator將鼠標(biāo)事件作為輸入,并修改用于控制用戶(hù)視口的osg::Camera視口矩陣。
TrackballManipulator派生自osgGA::GUIEventHandler類(lèi),是虛基類(lèi),無(wú)法實(shí)例化,但用戶(hù)可以從GUIEventHandler派生自己的類(lèi),以實(shí)現(xiàn)各種基于GUI事件的操作。要實(shí)現(xiàn)鼠標(biāo)控制的選擇操作,可以從GUIEventHandler派生新的類(lèi),并重載
GUIEventHandler::Handle()方法,以接收鼠標(biāo)事件。然后用戶(hù)可以創(chuàng)建新類(lèi)的實(shí)例并將其關(guān)聯(lián)到應(yīng)用程序的觀(guān)察視口。
Virtual bool GUIEventHandler::Handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter & aa);用戶(hù)實(shí)現(xiàn)的Handle()方法可以接收來(lái)自GUIEventAdapter的各種GUI事件,包括鼠標(biāo)事件。GUIEventAdapter類(lèi)的頭文件中定義了枚舉類(lèi)型EventType,用戶(hù)程序可以從中選擇自己需要的GUI事件。使用GUIEventAdapter.getEventType()方法可以得到當(dāng)前的事件類(lèi)型。GUIActionAdapter是用戶(hù)返回給GUI系統(tǒng)的程序接口。當(dāng)遇到鼠標(biāo)選擇的操作時(shí),用戶(hù)將用于選擇事件的GUIEventHandler關(guān)聯(lián)到視口類(lèi),則視口類(lèi)就是一個(gè)GUIActionAdapter。用戶(hù)需要使用他來(lái)實(shí)現(xiàn)當(dāng)前視口與場(chǎng)景之間的交互。
?
在渲染視口之前,用戶(hù)往往會(huì)創(chuàng)建一個(gè)GUIEventHandler派生類(lèi)的實(shí)例,并使用Viewer::addEventHandler()將其關(guān)聯(lián)到視口。一個(gè)視口可以有多個(gè)事件處理器,Viewer將事件處理對(duì)象添加到一個(gè)事件處理列表中。運(yùn)行時(shí)Viewer將調(diào)用每個(gè)GUI事件的handle()函數(shù),直到其中一個(gè)的handle()函數(shù)返回true為止。
?
要實(shí)現(xiàn)接收鼠標(biāo)事件并實(shí)現(xiàn)用戶(hù)選擇的功能,需要經(jīng)過(guò)以下幾個(gè)步驟:
1.?????? 從GUIEventHandler繼承新的類(lèi),重載handler()方法。
2.?????? 在handler()方法中檢查GUIEventAdapter參數(shù)傳遞的事件類(lèi)型,并針對(duì)需要的事件類(lèi)型執(zhí)行相應(yīng)的操縱。方法返回true時(shí)將阻止其他事件處理器繼續(xù)接受事件消息。
3.?????? 在渲染之前,創(chuàng)建事件處理器的實(shí)例,并使用addEventHandler()方法添加到視口中。Osg將會(huì)把視口作為GUIActionAdapter參數(shù)傳遞給handler()方法。
?
?
交集
Osg使用一種多胞體(polytope)的金字塔形包圍盒代替射線(xiàn)。這種金字塔的頂峰位于視點(diǎn),其中心軸直接穿過(guò)鼠標(biāo)(光標(biāo))的位置。它距離視點(diǎn)的寬度是由視場(chǎng)和程序控制的寬度參數(shù)決定的。
?
osgUtil::IntersectionVisitor類(lèi)繼承自NodeVisitor,它可以監(jiān)測(cè)每個(gè)定點(diǎn)的包圍盒與交集包圍盒的關(guān)系,并允許在某個(gè)子圖形不可能存在有交集的子節(jié)點(diǎn)時(shí),跳過(guò)該子圖形的遍歷。
?
用戶(hù)可以設(shè)置IntersectionVisitor類(lèi)并使用幾種不同的幾何結(jié)構(gòu)進(jìn)行交集檢測(cè)。其構(gòu)造函數(shù)使用osgUtil::Intersector作為輸入?yún)?shù),Intersector定義了選擇操作的幾何體并執(zhí)行實(shí)際的交集操作。Intersector是一個(gè)純虛基類(lèi),osgUtil庫(kù)從中派生了許多代表不同幾何結(jié)構(gòu)的新類(lèi)。
?
?
有些程序需要拾取單獨(dú)的頂點(diǎn)和多邊形,而有些程序只需要簡(jiǎn)單的獲取那些包含了被選節(jié)點(diǎn)的Group或Transform父節(jié)點(diǎn)。IntersectionVisitor返回osg::NodePath對(duì)象來(lái)滿(mǎn)足這些要求。NodePath是一個(gè)std::vector<osg::Node>向量,它表示沿著根節(jié)點(diǎn)到葉節(jié)點(diǎn)﹑呈現(xiàn)出一定排列層次的節(jié)點(diǎn)路線(xiàn)。如果用戶(hù)程序需要獲取中的父節(jié)點(diǎn),只需要從后到錢(qián)搜索滿(mǎn)足要求的節(jié)點(diǎn)即可。
?
要實(shí)現(xiàn)osg中的鼠標(biāo)選擇操作,需要按照如下的步驟編寫(xiě)代碼:
1.?????? 創(chuàng)建并設(shè)置PolytopeIntersector,其中的鼠標(biāo)位置應(yīng)當(dāng)使用GUIEventAdapter中經(jīng)過(guò)歸一化的數(shù)據(jù)。
2.?????? 創(chuàng)建IntersectionVisitor對(duì)象,并將PolytopeIntersector作為其構(gòu)造函數(shù)的輸入?yún)?shù)。
3.?????? 由場(chǎng)景圖形的根節(jié)點(diǎn)加載IntersectionVisitor,一般來(lái)說(shuō)是通過(guò)Viewer中的Camera對(duì)象,
如下面的代碼:
iv是一個(gè)IntersectionVisitor對(duì)象
viewer.getCamera()->accept(iv);
4.????? 如果PolytopeIntersector的返回值包含了交集,那么可以獲取返回的NodePath并搜索符合要求的節(jié)點(diǎn)。
總結(jié)
- 上一篇: html绘制直角坐标系,canvas画直
- 下一篇: h5调用微信sdk步骤