祝新霞,馬明棟
(1.南京郵電大學 通信與信息工程學院,江蘇 南京 210003; 2.南京郵電大學 地理與生物信息學院,江蘇 南京 210023)
現如今,虛擬現實已滲透到人們生活的方方面面[1]。它被認為是一種先進的科學技術,相較于傳統的人機界面以及流行的視窗操作。人們采用一種全新的方式,即通過計算機對復雜數據進行可視化操作與交互,極大地促進了虛擬現實技術的發展[2],廣泛應用于科學計算可視化、城市規劃、建筑設計、廣告宣傳、醫療、場景仿真等領域[3]。場景漫游是虛擬現實的一個重要應用部分,具有人機實時交互特性,可以在虛擬場景中自由行走,不受時間和空間的限制,實現真正意義上的交互,給人以身臨其境的感覺。
文中采用OpenSceneGraph三維圖形引擎實現了一個虛擬校園場景漫游系統,同時研究了漫游過程中的碰撞檢測技術。該系統的實現和設計充分體現了OSG在主流三維仿真平臺的優勢和潛力,其開源、面向對象的優點,可以加快開發過程,提高渲染效率。
OSG具有支持大規模場景的分頁、粒子系統與陰影、多線程、多顯示的渲染,以及支持各種文件格式等特性[4]。OSG是一個高性能的開源的跨平臺的圖形開發三維引擎,諸如飛行器仿真、虛擬現實、科學計算可視化等高性能圖形應用程序的開發,就是利用OSG設計實現的[5]。OSG結合Visual C++開發,其基于場景圖的概念,為圖形程序的開發提供場景管理和渲染優化功能,同時OSG是一個基于OpenGL函數庫的面向對象框架,促使開發者從實現和優化底層圖形的調用功能的實現中解放出來,為快速開發圖形應用程序提供了許多附加的實用工具。
(1)開源。
OSG跟目前市面上一些商業化的三維圖形引擎不同,它的所有源碼都是遵循OSGPL開源協議開發,基于OSG的程序和軟件的使用與發布無需額外費用。
(2)源碼質量高。
基于OSG的開源特點,它的源碼歷經了無數優秀開發人員的測試和修改,其程序架構和執行效率都有較好的提升。
(3)跨平臺操作。
OSG支持的操作平臺包括Windows、UNIX、Linux、MacOSX、IRIX、Solaris等多種操作系統,可以跨平臺操作,具有較強的可移植性。
(4)可擴展性強。
OSG提升了強大的可擴展能力,其支持節點擴展、屬性渲染、回調和交互事件,并支持第三方插件。
OSG核心庫(core library)是OSG存在的基礎,核心場景數據庫和操作場景圖形的組織和管理都是由OSG核心庫完成的,并且為導入外部數據庫提供接口[6]。OSG核心庫主要由以下五個庫構成:
osg庫:作為最基本數據庫,提供基本場景圖形構建場景圖節點類、幾何體類,用作向量和矩陣運算類。
osgUtil庫:又叫工具庫,提供了通用的公用類,用于場景圖及內容操作,統計和優化場景圖形數據,以及渲染器的創建。
osgDB庫:讀寫數據庫,也是一個文件工具類,提供場景中讀寫數據的工作。通過遍歷場景圖層次結構以完成數據處理工作,實現場景圖管理。
osgViewer庫:管理視窗庫,提供場景中視口及可視化內容的管理,有利于OSG與各種GUI結合。
osgGA庫:用于改寫界面事件。
場景圖是用于游戲和計算機圖形學等軟件的數據結構設計方法,即在抽象的場景中繪制元素組織結構、相互關系[7]。實際上大規模管理場景圖形通常使用樹結構或圖結構組成一組節點集。當前大多數渲染引擎組織其空間數據集皆采用自頂向下且分層的樹狀結構,以提高渲染效率。例如渲染場景中包含一輛卡車和一條路況順暢的馬路,由于場景圖的節點不代表幾何關系,可申請一個節點用來表示移動,如圖1所示。

圖1 場景圖
根節點一般處于場景圖結構的頂部,由根節點延伸至各組節點,各自的幾何信息以及用來控制其外觀的渲染狀態信息均包含在組節點中。這些節點皆可沒有或含有多個子成員。場景圖的底端展示了組成場景中各個葉節點的物體實際信息。圖2表示典型的場景圖樹型結構的組織方式。
圖2 典型場景圖樹型結構
整個三維場景結構可以由根節點表示,物體狀態切換、矩陣變換、細節層次等屬性信息可由根節點延伸的組節點表示;管理屬性信息的開關節點(osg::Switch)、變換節點(osg::Transform)、細節層次節點(osg::LOD)等是由組節點派生出來的;葉子節點(osg::Geode)反映場景空間結構和對象狀態,數據節點之間共有行為和屬性一般通過葉子節點提取[8]。
場景圖形結構是建在底層API函數之上的,它為3D程序提供了所需的空間數據組織能力及其他特性。OSG程序層次結構如圖3所示。
圖3 典型OSG程序結構層次模型
三維場景處于漫游系統中時被認為是靜止的。在實際設計時,使用相機從場景的不同位置和不同角度去觀察,然后把相機從不同位置和不同角度拍攝到的“場景”輸出到屏幕,就完成了虛擬場景漫游效果[9]。三維圖像顯示過程如圖4所示。

圖4 三維圖像顯示流程
人們通常是通過眼睛來觀察事物的,當視點發生移動時,周圍的景物相對于視點在做反向移動,該過程反應到大腦,在大腦中形成場景漫游效果。漫游功能實現在于漫游器的選擇。在OpenSceneGraph中,既可用默認漫游器,也可使用自定義的漫游器。
Viewer是場景的核心管理器,即漫游器。在漫游過程中必須根據響應事件的類osgGA::GUIEventHandler來響應操作。Viewer通過實時修正場景相機(Camera類)的觀察矩陣(代表觀察者位置和姿態的矩陣)方法來實現平滑的場景瀏覽效果[10],因此自定義漫游器就是設置相機觀察矩陣的過程。osgGA::CameraManipulator類由osgGA::GUIEventHandler類派生而來,Viewer可以通過設置矩陣的公共接口和響應得到有效控制。一般的場景操作如圖5所示。

圖5 一般的場景操作
矩陣為OSG提供了一個通用模型。在OSG中,不僅所有視圖矩陣操作是通過矩陣完成,而且不同相機間的交互也是通過矩陣完成[11]。OSG osgGA::CameraManipulator的派生類用來實現OSG的相機操作功能,而控制相機的關鍵是實現osgGA::CameraManipulator類的4個純虛函數:
將水熱預處理后的微藻生物質離心15 min,離心機轉速為 5 000 r·min-1(RCF=5 000×g),取離心后的固體物質用于DSC的實驗分析。
virtual voidsetByMatrix(const osg::Matrixd & matrix){} /*設置相機的觀察矩陣*/
virtual voidsetByInverseMatrix(const osg::Matrixd& matrix){} /*設置相機的視圖矩陣*/
virtualosg::Matrixd getMatrix() const {} /*獲取相機的觀察矩陣*/
virtualosg::Matrixd getInverseMatrix() const{}/*獲取相機的視圖矩陣*/
調用getMatrix來獲得SetByMatrix函數所需的矩陣,實現向下一個照相機傳遞矩陣。當從一個相機切換到另一個相機時調用setByMatrix函數,將上一個相機的視圖矩陣傳過來,據此設置相機的初始位置。
getInverseMatrix是變換矩陣的逆矩陣,它會在更新遍歷中被場景相機調用,返回當前的視圖矩陣。利用這個方法對時間進行處理,可以改變場景狀態,進而在調用getInverseMatrix矩陣時,改變場景內相機的位置情況[12]。這個函數在void Viewer::updateTraversal()中被調用。
_camera->setViewMatrix(_cameraManipulator->getInverseMatrix());
另外,handle作為主要控制器函數也是必須的。
virtualbool handle(const osgGA::GUIEvent Adapter & ea,osgGA::GUIActionAdapter& us);
handle方法含有兩個參數,分別是GUI事件的提供者和對GUI進行反饋,可以讓GUIEventHandler根據輸入事件操作GUI。若要對事件進行處理,可由GUIEventHandler繼承得到自己的類,然后將handle方法覆蓋,在繼承的類中對事件進行處理。osgProducer::Viewer類維護一個GUIEventHandler隊列,在該隊列里事件依次傳遞,handle函數返回值決定此事件是否繼續讓GUIEventHandler處理,若返回true,停止事件處理;否則GUIEventHandler繼續對該事件進行處理[13]。圖6為實現方向鍵控制相機視口的效果圖。
碰撞問題是由用戶的交互和物體的運動產生的。實時檢測物體的碰撞并計算出相應的碰撞反應,更新顯示結果來避免發生與現實情景不符的穿透現象[14]。

圖6 方向鍵控制相機視口的效果圖
處理碰撞檢測的方法有兩種:一是求交器檢測法,二是包圍盒檢測法。求交器檢測法是將遍歷器綁上求交器,以實現整個場景的求交過程。常用的有直線求交器和多邊形求交器。因為直線求交器只檢測直線與多邊形的碰撞事件,故多用于判斷鼠標點擊事件。該系統要實現既定功能,應使用多邊形求交器。設置初始值時需同時設置被檢測的多邊形,若此多邊形每幀發生變化,則每幀都需重新設定多邊形求交器的參數,就是polytope類型變量,以指定多邊形網格。這一過程消耗時間較長,又因其默認位置為坐標原點,所以需要獲取真實的世界坐標。
OSG中包圍盒檢測方法也有兩種,分別是用getBound()函數返回的球形包圍盒和用getBoundingBox()函數返回的立方體包圍盒。getBoundingBox()的函數唯獨Drawable節點含有,但所有Node節點卻皆含getBound()函數,故MatrixTransform節點的getBound()函數包含位置旋轉信息。因為MatrixTransform節點掛載實體節點,所以只能使用球體包圍盒方法。但球體包圍盒的缺點是范圍不準確,因此得到的數據可能比實際物體稍微大一點兒。
該系統采用直線求交器檢測方法。osg::LineSegment為線段類,表示一個起點和終點構成一條線段,如:osg::ref_ptr
在虛擬場景中,加快顯示畫面的速度可通過有效管理和組織虛擬場景,提高場景漫游效率來實現。OSG可以非常簡單方便地對虛擬場景進行管理和漫游,是目前技術較先進和性能較好的虛擬現實開發包。文中通過實踐場景漫游的過程,驗證了OSG對虛擬場景的漫游原理和發生碰撞時的檢測方法,為以后在工程實踐的應用提供了重要的參考依據。

圖7 碰撞檢測前后效果圖
參考文獻:
[1] 王 銳,錢學雷.OpenSceneGraph三維渲染引擎設計與實踐[M].北京:清華大學出版社,2009.
[2] 肖 鵬.OpenSceneGraph三維渲染引擎編程指南[M].北京:清華大學出版社,2010.
[3] MARTZ P.OpenSceneGraph快速入門指導[M].王 銳,錢學雷,譯.北京:清華大學出版社,2006.
[4] 楊石興,曹明亮.Step Into OpenSceneGraph[M].鄭州:鄭州大學虛擬實現實驗室,2014.
[5] 徐 凌.基于OpenSceneGraph引擎的漫游系統的研究與實現[D].武漢:武漢理工大學,2008.
[6] 溫轉萍,申閆春.基于OSG的虛擬校園漫游系統的設計與實現[J].計算機技術與發展,2009,19(1):217-220.
[7] SHREINER D,WOO M,NEIDER J,et al.OpenGL編程指南[M].鄧鄭詳,譯.第4版.北京:人民郵電出版社,2005.
[8] 申閆春,朱幼虹,曹 莉,等.基于OSG的三維仿真平臺的設計與實現[J].計算機仿真,2007,24(6):207-211.
[9] 張艷麗,譚同德,趙新燦,等.基于OSG的虛擬化學實驗平臺的構建設計[J].計算機工程與設計,2010,31(12):2909-2913.
[10] 楊 曉,廉靜靜,張新宇.基于OSG的虛擬場景中包圍盒碰撞檢測的研究[J].計算機技術與發展,2011,21(9):32-34.
[11] YUAN P,WANG S,ZHANG J,et al.Virtual reality platform based on open sourced graphics toolkit OpenSceneGraph[C]//International conference on computer-aided design and computer graphics.[s.l.]:IEEE,2007:361-364.
[12] HIGHT J,NOVAK J.Game development essentials:game project management[M].[s.l.]:Gengage Learning,2010.
[13] ZLATANOVA S,RAHMAN A,SHI W.Topological models and frameworks for 3D spatial objects[J].Computers & Geosciences,2004,30(4):419-428.
[14] 孫 倩,劉晶晶.OSG視景仿真技術應用[J].中國科技信息,2017(3):18-20.