摘 要: 碰撞檢測是三維漫游中的一項(xiàng)重要功能,。通過面向?qū)ο髨D形渲染引擎(OGRE)構(gòu)建了一個(gè)模擬三維漫游系統(tǒng),,利用OgreNewt結(jié)合Newton庫在系統(tǒng)中實(shí)現(xiàn)碰撞檢測功能。碰撞檢測包圍盒均采用3DSMax創(chuàng)建,,利用OgreNewt中的碰撞檢測樹解析,,既保證了碰撞的精確性,又節(jié)省了編碼工作量,。適用于層次結(jié)構(gòu)較復(fù)雜的三維場景的加載和碰撞檢測,。
關(guān)鍵詞: 碰撞檢測; 三維漫游,; 面向?qū)ο髨D形渲染引擎
虛擬現(xiàn)實(shí)是當(dāng)今計(jì)算機(jī)領(lǐng)域的一項(xiàng)熱門技術(shù),,其中一個(gè)重要功能是虛擬三維漫游,實(shí)現(xiàn)這一功能需要借助計(jì)算機(jī)圖形引擎,。OGRE[1]是一款專門處理三維場景的圖形引擎,,具有開源免費(fèi)、跨平臺(tái)等多種優(yōu)點(diǎn),,目前在虛擬現(xiàn)實(shí)領(lǐng)域已有非常廣泛的應(yīng)用[2-3],。
實(shí)現(xiàn)三維漫游需要考慮的一個(gè)重要問題是碰撞檢測,OGRE引擎本身不具備這項(xiàng)功能,,需要借助第三方引擎實(shí)現(xiàn),,常用的第三方引擎庫有Newton[4]、ODE[5]等,。Newton在碰撞檢測方面性能更出色,,它是一款開源免費(fèi)的碰撞檢測引擎庫,OgreNewt是對Newton庫的一層面向?qū)ο蠓庋b,??梢越Y(jié)合OgreNewt和OGRE,在三維場景中實(shí)現(xiàn)碰撞檢測功能,。本文主要探討如何在OGRE基礎(chǔ)上,,結(jié)合OgreNewt及Newton庫,實(shí)現(xiàn)具有碰撞檢測功能的三維漫游系統(tǒng),。
1 OGRE,、Newton和OgreNewt
OGRE是用C++開發(fā)的跨平臺(tái)的3D引擎,底層基于OpenGL和DirectX實(shí)現(xiàn),,具有高效的三維場景管理性能,,能很好地兼容第三方庫以實(shí)現(xiàn)一些特定功能。一個(gè)基本的OGRE系統(tǒng)主要包括Root、SceneManager,、Entity,、SceneNode、Material和Camera等幾部分,。Root是整個(gè)系統(tǒng)的入口點(diǎn),,通過它可以獲取系統(tǒng)中的其他對象。Entity是三維物體模型,,Material是模型的材質(zhì),,每個(gè)Entity 都掛載到一個(gè)SceneNode上,所有SceneNode共同組成一個(gè)樹狀結(jié)構(gòu),,由SceneManager統(tǒng)一管理,。通過Camera來實(shí)現(xiàn)觀看場景。
OGRE引擎通過OgreNewt與Newton庫銜接,。OgreNewt通過Newton庫中的一些基本的元素來描述物理世界,,主要包括World、Collision和Body等,。World是最基本的類,,通過它可以建立一個(gè)空間,所有其他物體都在這個(gè)空間里創(chuàng)建,??臻g中的物體參加碰撞檢測時(shí)需要有一個(gè)包圍盒,通過包圍盒計(jì)算來判斷是否發(fā)生了碰撞,,Collision用于定義包圍盒的形狀,,基本形狀有Boxes、Ellipsoids,、Cylinders,、Capsules等。Body用于定義碰撞檢測包圍盒的實(shí)體,,它可以與空間中的其他實(shí)體相互作用,比如發(fā)生碰撞,、摩擦等,。它需要根據(jù)Collision定義好的形狀來創(chuàng)建。此外還有Joint,、MaterialID,、MaterialPair等,都有其他用途。
2 三維漫游系統(tǒng)
2.1虛擬場景構(gòu)建
建立一個(gè)三維漫游系統(tǒng),,首先要構(gòu)建虛擬場景,,主要步驟如下:
首先建立并取得Root,再讀取所有資源路徑并添加到資源組管理器中,接著創(chuàng)建場景管理器,、相機(jī)并為相機(jī)創(chuàng)建視口,;然后創(chuàng)建場景,解析資源配置文件并加載所有資源,。漫游需要鍵盤,、鼠標(biāo)等外設(shè)控制,需要在程序中創(chuàng)建幀監(jiān)聽器,,以監(jiān)聽每一幀的變化,;最后是對場景進(jìn)行渲染顯示。
2.2 碰撞檢測
進(jìn)行三維漫游時(shí),,如果發(fā)生碰撞,,需要添加碰撞檢測?;贜ewton庫,,通過OgreNewt建立碰撞檢測步驟及代碼如下:
(1)創(chuàng)建World
首先要?jiǎng)?chuàng)建一個(gè)碰撞檢測空間:
OgreNewt::World* m_World = new OgreNewt::World();
(2)為漫游者添加碰撞檢測包圍盒
由于漫游采用第一人稱視角,可以有一個(gè)基本形狀來表示漫游者,。這里通過一個(gè)球體來代替:
OgreNewt::CollisionPrimitives::Ellipsoid sphere(m_pWorld, Ogre:: Vector3(PLAYER_WIDTH/2.0, PLAYER_WIDTH/2.0,
PLAYER_WIDTH/2.0));
m_pPlayerBody=new OgreNewt::Body(m_pWorld, &sphere);
由于這個(gè)球體代替漫游者,,它與別的物體碰撞時(shí)會(huì)有力的作用,因此,,它既有質(zhì)量也有慣性,。這些值必須要設(shè)置:
Ogre::Vector3 inertia = OgreNewt::MomentOfInertia::CalcSphereSolid(PLAYER_WEIGHT, PLAYER_WIDTH / 2.0);
m_pPlayerBody->setMassMatrix(PLAYER_WEIGHT,inertia);
(3)為其他物體添加碰撞檢測包圍盒
碰撞的作用是相互的,不僅漫游者需要碰撞檢測包圍盒,,場景中其他所有物體都需要,。在大規(guī)模三維場景中,三維模型比較多,,形狀也各不相同,,因此完全在程序中為每個(gè)物體按照其形狀創(chuàng)建包圍盒會(huì)極大增加代碼量;如果都用簡單的基本形狀來表示,,進(jìn)行碰撞時(shí)又不夠精確,。為了解決這一問題,利用碰撞檢測樹和3DSMax配合來實(shí)現(xiàn),。首先在空間中創(chuàng)建一個(gè)碰撞檢測樹場景解析器TreeCollisionSceneParser,,只需要將OGRE場景中的碰撞檢測根節(jié)點(diǎn)給它,它就會(huì)解析這個(gè)根節(jié)點(diǎn)所對應(yīng)的節(jié)點(diǎn)樹,,并將這棵樹上的所有子節(jié)點(diǎn)納入碰撞檢測范圍,。關(guān)鍵代碼如下:
Ogre::SceneNode* pRootNode =
Ogre::Root::getSingleton().getSceneManager(DEFAULT_
SCENE_MANAGER)
->getSceneNode(sCollisionRootNode.c_str());
OgreNewt::CollisionPrimitives::TreeCollisionSceneParser
parser(m_pWorld);
parser.parseScene(pRootNode, true);
OgreNewt::Body* pRootBody=new OgreNewt::Body(m_p
World, &parser);
pRootBody->attachToNode(pRootNode);
sCollisionRootNode即為碰撞檢測樹根節(jié)點(diǎn),場景中所有其他三維模型的碰撞檢測包圍盒應(yīng)作為子節(jié)點(diǎn)掛在這棵樹上,。這些包圍盒都在3DSMax中創(chuàng)建,。只要是納入碰撞檢測范圍的模型,,就為它添加一個(gè)副本,不是特別復(fù)雜的模型,,副本的形狀,、大小、位置可以與模型完全相同,;對于較復(fù)雜的模型,,可以通過基本形狀組合成模型輪廓作為副本。這些副本就是模型的包圍盒,。然后將這些包圍盒作為子節(jié)點(diǎn)掛在sCollisionRootNode下,,最后整個(gè)場景就會(huì)形成一棵碰撞檢測樹,樹上的所有包圍盒在碰撞時(shí)都會(huì)被程序檢測到并參加計(jì)算,。
(4)注冊回調(diào)函數(shù)
漫游者與其他物體發(fā)生碰撞時(shí)可能會(huì)發(fā)生位置,、方向等的變化,這些變化需要被及時(shí)獲知并實(shí)時(shí)顯示,,這一功能可以通過回調(diào)函數(shù)實(shí)現(xiàn),。這里定義兩個(gè)回調(diào)函數(shù),一個(gè)回調(diào)函數(shù)用于在漫游者受到其他物體的作用力時(shí)產(chǎn)生一個(gè)速度,。主要代碼為:
void CBasicInputListener::CustomForceAndTorqueCallback
(OgreNewt::Body* me)
{ SceneNode* pPlayerNode =
Root::getSingleton().getSceneManager(DEFAULT_
SCENE_MANAGER)->
getSceneNode(DEFAULT_CAMERA_NODE);
me->setVelocity(pPlayerNode->getWorldOrientation()*
m_TranslateVector + Vector3(0, -DEFAULT_GRAVI-
TY, 0));
}
另一個(gè)回調(diào)函數(shù)用于漫游者發(fā)生變化時(shí),。比如相機(jī)切換或漫游者移動(dòng),都會(huì)發(fā)生位置方向的改變,,因此需要及時(shí)進(jìn)行變化,,主要代碼如下:
void CBasicInputListener::CustomTransformCallback(Ogre
Newt::Body* me, const Quaternion& orient, const
Vector3& pos)
{ ……
pPlayerNode->setPosition(pos.x,
pos.y + PLAYER_HEIGHT - PLAYER_WIDTH
/2.0, pos.z);
……
}
3 運(yùn)行效果
在Windows平臺(tái)下,基于OGRE1.4.9,、OgreNewt 0.11和Newton1.5.3實(shí)現(xiàn)了一個(gè)具有碰撞檢測的模擬三維漫游系統(tǒng),,其中的三維場景模型采用3DSMax 8創(chuàng)建。圖1為漫游時(shí)與墻壁發(fā)生碰撞的截圖,,圖2為與樹碰撞時(shí)的截圖,。當(dāng)發(fā)生碰撞時(shí),漫游者將無法前進(jìn),,必須向其他方向移動(dòng)才能繞過阻擋物體,。墻壁的三維模型不是很復(fù)雜,因此碰撞檢測包圍盒的形狀和墻壁相同,。而樹的形狀比較復(fù)雜,,如果用完全相同的形狀會(huì)極大增加計(jì)算量,因此在3DSMax中為其添加了一個(gè)球體加圓柱體的輪廓作為包圍盒,,如圖3所示為樹的包圍盒網(wǎng)格。
本文介紹了如何在OGRE引擎中,,通過OGRENewt結(jié)合Newton庫,,創(chuàng)建一個(gè)具有碰撞檢測的三維漫游系統(tǒng)的方法,,并實(shí)現(xiàn)了一個(gè)模擬系統(tǒng)。所使用的引擎庫皆為開源免費(fèi),,并具有較高的效率和良好的體驗(yàn)效果,,可以在實(shí)際中應(yīng)用。
參考文獻(xiàn)
[1] http://www.ogre3d.org/
[2] Xie Mei, Zhen Zheng, Zhang Fan, et al. A cross-platform extendable 3D Virtual Reality system based on OGRE and Python[C]. Communications, Circuits and Systems, 2009. ICCCAS 2009:502-506.
[3] Liu Xiuling, Du Huanping, Wang Hongrui,et al. Design and development of a distributed Virtual Reality system[C]. Machine Learning and Cybernetics, 2009:889-894.
[4] http://newtondynamics.com/.
[5] 高嵩,,陳先橋,,楊菊.基于OGRE和ODE的駕駛模擬系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].交通與計(jì)算機(jī),2006,24(1):101-104.