2013年7月29日 星期一

程設再開!這次是OgreBullet


好久沒有動Ogre相關的東西了
這次是另一個物理引擎Bullet與Ogre的結合:OgreBullet
之所以想試Bullet是因為它有SoftBody這個有趣的東西
可以模擬軟的東西,如草與繩子的擺動(線)、布(面)、皮球與輪胎(體)等

可是實際下載使用後,就像當初看到Ogre的Water範例程式碼一樣
果然沒這麼簡單,一大塊不知道寫什麼鬼的程式碼
然後OgreBullet只支援RigidBody[1],並無法直接使用SoftBody
這也是意料中事,所以只能一步一步來啦

[1]Rigid Body就是國中物理所提的剛體,不會形變的物體。

拜討論區上Building OgreBullet with OgreSDK 1.8.1 on Windows這篇文章所賜
從原始碼一步步建立相關的函式庫檔案時輕鬆不少
Ogre使用舊版的1.7.4,編譯器也是從上次就沒更新的MinGW
仍然建立的很順
不過要自己寫一個範例來跑跑時,則遇到了一點點問題
我這「肉腳」看不懂OgreBullet本身附檔範例怎麼寫
所幸官網上OgreBullet Tutorial 2寫的很簡潔明白
很快的也搞定了第一個範例「丟東西」

因為有使用過另一個OgreNewt的函式庫,兩者不免拿來比較一下
整體來說OgreBullet與之前使用的OgreNewt大體上都差不多
都有DynamicWolrd(World),RigidBody(Body),Shap(Collision), Constraint(Joint)等
以Wrapper函式庫[2]來說,OgreBullet一開始實在用不習慣,太散亂了
本身就分為Dynamic與Collision兩個部分,而OgreNewt就比較單一,只產生一個檔案。
同時OgreNewt只要include一個標頭檔則可使用全部功能,感覺方便很多
OgreBullet使用不同的功能要個別include標頭檔,就覺得比較麻煩。
不過Bullet分為兩個部分也是有好處,它可以允許Collision單獨存在
對於只想偵測碰撞有無,而不需要物理模擬時,這是個不錯的方案。

[2]Wrapper(包裝)函式庫是指提供兩個不同的函式庫的一個介面。
   因為它會把另一個輔助的函式庫包起來看不到原始函數,所以叫Wrapper。

另外OgreBullet與OgreNewt相比,OgreBullet函式與Bullet對應有點差
舉例來說,我想讓一個物體旋轉時,
前者可以直接由OgreNewt函式設定轉速
而後者卻要先取出bullet本體的RigidBody才能處理,
等於完全跳過Wrapper,從底層去處理
我個人認為,這麼單純的功能應該是身為「介面」就可以處理掉的,
既然要直接叫原始函式出來的話,那介面存在就不太必要了嘛
或許也因為如此,才會有另一個輕量化的工具btOgre出現
這個下次再提。

雖然OgreBullet有著不少不盡我意的地方,
上面都是些抱怨連連的描述。
但是畢竟是個連結Ogre與Bullet方便的工具
從這邊開始學Bullet就跟從ExampleApplication與ExampleFramelistener學Ogre一樣
簡單方便但有些限制
而且,除了跟OgreNewt一樣有載入Entity就可以產出ConvexHull的Shape外
它還有一個可以產出更複雜,更貼近3D模型本身的物件GImpactConcaveShape可用
跟OgreNewt的TreeCollision很類似,但OgreBullet的是可以移動的
而TreeCollision只能是靜態物件,這就差很多
只是要使用這函數沒那麼簡單,以下是範例
//這是重點,要註冊GImpactCollision讓碰撞運算有效
//不然就會看到它穿過去
btCollisionDispatcher * dispatcher = 
static_cast(mWorld->getBulletCollisionWorld()->getDispatcher());
btGImpactCollisionAlgorithm::registerAlgorithm(dispatcher);

//產生Ogre的Entity與SceneNode
ent = mSceneMgr->createEntity("HitBody","athene.mesh");
ent->setCastShadows(true);
node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
node->attachObject(ent);

/*
使用OgreBullet的AnimatedMeshToShapeConverter
這個物件的作用是輸入Entity取得Mesh的詳細資料,
便於算出ConvexHull或更複雜的GImpactCollision
其實用另一個StaticMeshToShapeConverter也行,並不影響結果
*/
OgreBulletCollisions::AnimatedMeshToShapeConverter *animeMesh = 
new OgreBulletCollisions::AnimatedMeshToShapeConverter(
  ent, //很單純就載入Entity,裡面會去取得所需要的Mesh資訊
  node->_getFullTransform()); /*載入此Entity的Matrix4,
也就是取得大小與位置,
這邊直接用_getFullTransform()從node取得最方便*/

//使用createConcave產生我們所要的GImpactConcaveShape
OgreBulletCollisions::GImpactConcaveShape *concaveMeshShape = animeMesh->createConcave();

//最後就是產生一個Rigid Body
OgreBulletDynamics::RigidBody *specialBody = 
new OgreBulletDynamics::RigidBody(
                   "specialBody",
                   mWorld);
//然後把這碰撞偵測的外型載入
specailBody->setShape(node,//與Ogre的node連結
    concaveMeshShape, //
    0.6f,    // 物體的恢復係數(碰撞動能損失)
    0.8f,    // 物體磨擦力
    1.0f,    // 物體質量
    position,  // 物體啟始位置
    node->getOrientation());// 物體的方向
/* ===完成=== */
然後你就可以得到一個非常貼近模型形狀的碰撞偵測區
嘖嘖,真是好用啊
不過我還是想玩SoftBody特效,希望花一週都搞定Bullet基本
下次再發表就是SoftBody的Demo影片(自己的)


沒有留言: