雖然只寫不過三個範例:
其它外型的建立,旋轉力量的給予,與Constraint的建立。
但整體習性大概已知一二
大概剩下callback使用(碰撞處理與外力給予)、角色控制與車輛產生的部分吧
試到這裡就決定改用上一篇文章提過的BtOgre
BtOgre是個只有四個檔案構成的介面工具,
目前發掘它最大的用處有三點,就是處理:
1、entity轉shape
2、node轉btMotionState
3、debug用drawing在Ogre顯示
http://www.ogre3d.org/forums/viewtopic.php?f=5&t=46856
它支援的是原生的Bullet使用
換言之,要在Ogre上比較簡單的玩Soft Body應該只能靠它了
因為爬過OgreBullet的原始碼,它本身只有使用btDiscreteDynamicsWorld
而Sofy Body要用的是btSoftRigidDynamicsWorld
除非整個置換掉OgreBullet裡的,也就是大修原始碼,不然很難做到了。
BtOgre裡的demo比OgreBullet裡所寫的,簡單非常多
甚至也比bullet裡的還要明快直接
一看就可以知道要怎麼使用一步一步啟用bullet
很可惜是已經爬完bullet的demos後才看到的
省不了什麼學習的時間
BtOgre的使用範例如下
首先是物理世界的建立
/* mBroadphase,mCollisionConfig, mDispatcher,mSolver這些是創建world前必要的物件 通常是建在範例物件的被保護成員 至於用途的話,mBroadphase應該是物理世界的大小設定, 其它三者詳細就不清楚 phyWorld當然就是btDiscreteDynamicsWorld */ mBroadphase = new btAxisSweep3( btVector3(-10000,-10000,-10000), btVector3(10000,10000,10000), 1024); mCollisionConfig = new btDefaultCollisionConfiguration(); mDispatcher = new btCollisionDispatcher(mCollisionConfig); mSolver = new btSequentialImpulseConstraintSolver(); //上面設定好後,產生我們需要的動態世界 //使用上面建立的物件 phyWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfig); //設定整個世界的重力,通常是-9.81(m/s^2) phyWorld->setGravity(btVector3(0,-9.81,0)); /* dbgdraw是BtOgre的DebugDrawer,用來顯示shap外型線條的 其實整個BtOgre是從這邊才開始用,前面都是bullet的用法而已 基本上這個去掉也不影響動作 */ dbgdraw = new BtOgre::DebugDrawer(mSceneMgr->getRootSceneNode(), phyWorld); phyWorld->setDebugDrawer(dbgdraw);
建立一個可動的剛體的部分如下:
/* 既然使用Ogre,建立一個entity與node的物體是標準程序 */ Ogre::Entity * ent; Ogre::SceneNode* node; ent = mSceneMgr->createEntity("FirstEnt","ogrehead.mesh"); ent->setCastShadows(true); node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->attachObject(ent); node->setPosition(0,10,0); /* 再來使用物理引擎第一步,建立碰撞用外型(Shape) 這邊就需要BtOgre的幫忙把Entity的Mesh轉成Shape 這邊使用ConvexHull的 Shape */ BtOgre::StaticMeshToShapeConverter animeMesh(ent); btCollisionShape* animeShape = animeMesh.createConvex(); /* 第二步給於物體質量與轉動慣量(inertia) */ btScalar mass = 10.0; btVector3 inertia; animeShape->calculateLocalInertia(mass, inertia); /* 第三步建立RigidBodyState,我覺得可以視為node與bullet的連結 */ BtOgre::RigidBodyState *rbState = new BtOgre::RigidBodyState(node); //最後就是產生body btRigidBody* defaultBody; defaultBody = new btRigidBody(mass,rbState,animeShape,inertia); //然後與世界做連結 phyWorld->addRigidBody(defaultBody); //完成建立
之後就看你怎麼玩啦
不過不要忘了
要更新整個世界的運算,不然東西還是不會動的
要在FrameLisnter裡的frameStarted或frameEnded裡
加上這一行:phyWorld->stepSimulation(evt.timeSinceLastFrame);
這樣就能動了
不過如果有使用debugdraw則要加上另外兩項東西
以frameStarted的範例如下:
bool frameStarted(const FrameEvent &evt) { //更新物理狀態 phyWorld->stepSimulation(evt.timeSinceLastFrame); //更新debugworld狀態 phyWorld->debugDrawWorld(); //原BtOgre有這一條,是按下F3時,才會顯示debugdraw dbgdraw->setDebugMode(mKeyboard->isKeyDown(OIS::KC_F3)); //更新debugdraw的線條 dbgdraw->step(); return ExampleFrameListener::frameStarted(evt); }
最後結束掉整個程式,或是重新建立物理世界時
記得照這順序進行刪除
1、先移除掉在world有用的所有的Constraint,再刪除
2、再移除掉所有的剛體,與btMotionState後,再刪掉
3、最後刪掉debugdrawer與wolrd,還有創建world的那堆物件
參考bullet與BtOgre的demo的綜合範例如下:
/* 這邊我用了bullet本身範例裡的處理法 先取得world本身的contraint數量 再一個一個從world移除後刪除 */ for (int i=phyWorld->getNumConstraints()-1; i>=0 ;i--) { btTypedConstraint* constraint = phyWorld->getConstraint(i); phyWorld->removeConstraint(constraint); delete constraint; } /* 這邊我用了OgreBullet本身範例裡的處理法 建立一組deque用來存建立過後RigidBody 最後用iterator的方法從world裡移除後刪除 */ std::deque::iterator itBody = mBodies.begin(); while (mBodies.end() != itBody) { phyWorld->removeRigidBody(*itBody); delete *itBody; ++itBody; } /* Shape的部分也是用OgreBullet本身範例裡的處理法 建立一組deque用來存建立過後Shape 不同於RigidBody,它只要刪除就好了 */ std::deque ::iterator itShape = mShapes.begin(); while (mShapes.end() != itShape) { delete *itShape; ++itShape; } //清除掉deque mBodies.clear(); mShapes.clear(); //刪掉debugdraw與world delete dbgdraw; delete phyWorld; //最後把建立world的物件全數刪除 delete mSolver; delete mDispatcher; delete mCollisionConfig; delete mBroadphase;
接下來就是繼學習,然後好好寫個小遊戲之類的吧
其實還蠻想再修一下天車的說
沒有留言:
張貼留言