Ogre中加入Bullet3物理引擎

时间:2024-05-22 12:34:10

一、bullet引擎简介

   Bullet是一个开源的物理模拟计算引擎,世界三大物理引擎模拟之一(另外两种是Havok和PhysX)。广泛应用于游戏开发和电影制作之中。Bullet也是AMD开放物理计划成员之一。

Bullet是一个跨平台的物理模拟计算引擎。支持Windows、Linux、MAC等多个平台。

二、bullet的主要函数

  在bullet中要实现物理世界需要三个函数,initPhysics()、stepSimulation()、exitPhysics()。

1、 initPhysics()函数

initPhysics()函数是初始化物理世界的一个函数。在该函数中首先要创建一个动态世界:btDiscreteDynamicsWorld* dynamicsWorld; 要想创建成功一个动态世界还需要四个参数,

分别为:

btBroadphaseInterface* broadphase;

btDefaultCollisionConfiguration*collisionConfiguration;

btCollisionDispatcher* dispatcher;

btSequentialImpulseConstraintSolver* solver;

这几个参数分别表示:

broadphase:一个阶段算法,目的是尽量剔除没有相互作用的对象对

collisionConfiguration:碰撞配置

dispatcher:碰撞调度器对象

solver:创建解算器,用于求解约束方程。

这四个类只需要实例化当做参数传入创建一个动态物理世界,这就成功的创建了一个空的动态物理世界,

 

     然后再在空的物理世界中加入其它的属性,首先加入一个重力,通过setGravity()设置物理世界的重力。接下来创建两个刚体btRigidBody* fallRigidBody; btRigidBody* groundRigidBody; 第一个刚体作为物理世界中的地面,第二个作为加入物理世界中的物体。创建一个刚要需要给刚体四个属性:mass(质量)、btDefaultMotionState(刚体的位置信息)btCollisionShape(刚体形状)fallInertia(惯性)。创建成功后,addRigidBody()加入到物理世界中。

 

     如此,初始化就完成了。

2、stepSimulation()

该函数主要是负责物理世界的更新,在每个时间段更新物理世界。这是Bullet中基类的一个虚函数,可以根据用户自己的需要进行重写调用。如果只是简单的加入一个物理世界的话,直接在framestarted函数中调用即可,但是要给它一个时间参数,让它知道什么时候更新。

 

3、exitPhysics()函数

该函数负责退出物理世界以及销毁物理世界。

该函数主要是在析构函数中调用。

 

 

三、Ogre中加入bullet物理引擎。

第一步、引用,引用该头文件,创建一个简单的物理世界所需的所有类和接口基本都在这里面。我在Ogre中提供的一个demo中加入了物理世界。首先将以及写好的initPhysics()函数放入setupContext()(建立场景的函数)中调用,(注:在这里调用该函数只是相当于创建了一个变量而没有使用它。)

 

第二步、接下来在ogre中的frameStarted()函数中调用stepSimulation()给它的参数为每一帧渲染完之后的时间(evt.timeSinceLastFrame 这是Ogre中已经封装好的直接用就可以)。

 

第三步、最后调用exitPhysics()函数销毁该物理世界即可。

 

第四步、物理世界只是相当于一种算法,一种规则,是抽象的,我们要想在demo中看到自己所创建的物理世界以及世界中我们创建的地面、物体刚体等需要用到bullet中提供的debugdraw的一个类,该类是bullet封装好让用户可以用来调试物理引擎的一个类。

 

 

 

 

 

 

 

 

 

 

 

 

 

成功加入物理世界后的demo截图:

 

 

 

 

 Ogre中加入Bullet3物理引擎

 

 Ogre中加入Bullet3物理引擎

 

 

 

 

 

 

 

 

 

四、具体实现代码

定义的几个类,作为参数传入建立动态物理世界

 

    btBroadphaseInterface* broadphase;

    btDefaultCollisionConfiguration* collisionConfiguration;

    btCollisionDispatcher* dispatcher;

    btSequentialImpulseConstraintSolver* solver;

    btDiscreteDynamicsWorld* dynamicsWorld;

    btCollisionShape* groundShape;

    btCollisionShape* fallShape;

    btRigidBody* fallRigidBody;

    btRigidBody* groundRigidBody;

    btRigidBody* fallRigidBody1;

    brPhysicsDebugDrawer* m_pPhysicDebugDraw;

 

 

initPhysics()函数

 

 

 

    void initPhysics()

    {

        //        helper->setUpAxis(1);

        //        helper->createPhysicsDebugDrawer(dynamicsWorld);

        //        if (dynamicsWorld->getDebugDrawer())

        //           dynamicsWorld->getDebugDrawer()->setDebugMode(btIDebugDraw::DBG_DrawWireframe+btIDebugDraw::DBG_DrawContactPoints);

        //创建broadphase阶段算法,目的是尽量的剔除没有相互作用的对象对

        broadphase = new btDbvtBroadphase();

        //创建碰撞配置对象以及碰撞调度器对象,使我们可以再各个阶段尝试不同的算法组合,目的是使用不同的算法和测试相同的碰撞

        collisionConfiguration = new btDefaultCollisionConfiguration();

        dispatcher = new btCollisionDispatcher(collisionConfiguration);

        //创建解算器,用于求解约束方程。得到物体在重力等作用下的最终位置的

        solver = new btSequentialImpulseConstraintSolver;

        //创建一个动态世界

        dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);

        //设置动力学世界的重力为Y轴向下方向

        dynamicsWorld->setGravity(btVector3(0,-10,0));

       

        //创建平面和一个球体,第一个参数是平面的法向,第二个参数是在法线方向的偏移,注意,动力学世界方向是Y轴下方向

        groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);

        //1为球体的半径

        fallShape = new btSphereShape(10);

       

        groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);

        //1为球体的半径

        fallShape = new btSphereShape(10);

       

        //       if (dynamicsWorld->getDebugDrawer())

        //           dynamicsWorld->getDebugDrawer()->setDebugMode(btIDebugDraw::DBG_DrawWireframe+btIDebugDraw::DBG_DrawContactPoints);

       

        //加入一个平面到动力学世界

        btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));

        btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));

        groundRigidBody = new btRigidBody(groundRigidBodyCI);//绑定操作

        dynamicsWorld->addRigidBody(groundRigidBody);

        //加入一个球体

        btDefaultMotionState* fallMotionState =

        new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)));

        btScalar mass = 1; //质量

        btVector3 fallInertia(0,0,0);//惯性

        fallShape->calculateLocalInertia(mass,fallInertia); //通过质量,这个函数计算出运动物体的惯性

        btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);

        fallRigidBody = new btRigidBody(fallRigidBodyCI);

        //       fallMotionState->setWorldTransform(btVector3(0, -10, 0));

        dynamicsWorld->addRigidBody(fallRigidBody);

        btVector3 v=fallRigidBody->getWorldTransform().getOrigin();

        std::cout<<"3213213213213211111"<<fallRigidBody->getWorldTransform().getOrigin().getX()<<std::endl;

        std::cout<<"ABCDE"<<fallRigidBody->getWorldTransform().getOrigin().getY()<<std::endl;

        std::cout<<"BDAZCZ"<<fallRigidBody->getWorldTransform().getOrigin().getZ()<<std::endl;

        //       helper->autogenerateGraphicsObjects(dynamicsWorld);

       

       

        btDefaultMotionState* fallMotionState2 =

        new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)));

        btScalar mass1 = 1; //质量

        btVector3 fallInertia1(0,0,0);//惯性

        fallShape->calculateLocalInertia(mass1,fallInertia1); //通过质量,这个函数计算出运动物体的惯性

        btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI1(mass1,fallMotionState2,fallShape,fallInertia1);

        fallRigidBody1 = new btRigidBody(fallRigidBodyCI1);

        //       fallMotionState->setWorldTransform(btVector3(0, -10, 0));

        dynamicsWorld->addRigidBody(fallRigidBody1);

        std::cout<<"3213213213213211111"<<fallRigidBody1->getWorldTransform().getOrigin().getX()<<std::endl;

        std::cout<<"ABCDE"<<fallRigidBody1->getWorldTransform().getOrigin().getY()<<std::endl;

        std::cout<<"BDAZCZ"<<fallRigidBody1->getWorldTransform().getOrigin().getZ()<<std::endl;

       

       

    }

 

 

initPhysics()函数调用位置:

void setupBody(SceneManager* sceneMgr)

    {

 

        initPhysics();

        //create main model

        mBodyNode = sceneMgr->getRootSceneNode()->createChildSceneNode(Vector3::UNIT_Y * CHAR_HEIGHT);

        mBodyEnt = sceneMgr->createEntity("SinbadBody", "Sinbad.mesh");

        mBodyNode->attachObject(mBodyEnt);

       

        //create swords and attach to sheath

        LogManager::getSingleton().logMessage("Creatingswords");

        mSword1 = sceneMgr->createEntity("SinbadSword1", "Sword.mesh");

        mSword2 = sceneMgr->createEntity("SinbadSword2", "Sword.mesh");

        mBodyEnt->attachObjectToBone("Sheath.L", mSword1);

        mBodyEnt->attachObjectToBone("Sheath.R", mSword2);

       

       

       

        nBodyNode = sceneMgr->getRootSceneNode()->createChildSceneNode(Vector3::UNIT_YCHAR_HEIGHT);

        std::cout<<"8888888"<<Vector3::UNIT_Y<<std::endl;

        mBodyEnt1 = sceneMgr->createEntity("SinbadBody1", "Sinbad.mesh");

        nBodyNode->attachObject(mBodyEnt1);

       

        //create swords and attach to sheath

        LogManager::getSingleton().logMessage("Creatingswords11");

        mSword11 = sceneMgr->createEntity("s1", "Sword.mesh");

        mSword22 = sceneMgr->createEntity("SinbadSword22", "Sword.mesh");

        mBodyEnt1->attachObjectToBone("Sheath.L", mSword11);

        mBodyEnt1->attachObjectToBone("Sheath.R", mSword22);

        LogManager::getSingleton().logMessage("Creatingthe chains");

        // create a couple of ribbon trails for theswords, just for fun

        NameValuePairList params;

        params["numberOfChains"] = "2";

        params["maxElements"] = "80";

        mSwordTrail = (RibbonTrail*)sceneMgr->createMovableObject("RibbonTrail", &params);

        mSwordTrail->setMaterialName("Examples/LightRibbonTrail");

        mSwordTrail->setTrailLength(20);

        mSwordTrail->setVisible(false);

        sceneMgr->getRootSceneNode()->attachObject(mSwordTrail);

       

       

        for (int i = 0; i < 2; i++)

        {

            mSwordTrail->setInitialColour(i, 1, 0.8, 0);

            mSwordTrail->setColourChange(i, 0.75, 1.25, 1.25, 1.25);

            mSwordTrail->setWidthChange(i, 1);

            mSwordTrail->setInitialWidth(i, 0.5);

        }

       

        mKeyDirection = Vector3::ZERO;

        nKeyDirection =Vector3::ZERO;

        mVerticalVelocity = 0;

        nVerticalVelocity = 0;

    }

 

 

stepSimulation()函数调用位置:

void addTime(Real deltaTime)

    {

        updateBody(deltaTime);

        updateAnimations(deltaTime);

        updateBodytwo(deltaTime);

        updateAnimationstwo(deltaTime);

        updateCamera(deltaTime);

        dynamicsWorld->stepSimulation(deltaTime);

//        physicsDebugDraw(1);

       

    }

bool frameStarted(const FrameEvent&evt)

    {

        //let character update animations and camera

        mChara->addTime(evt.timeSinceLastFrame);

        mChara->frameStarted(evt);

        mChara->physicsDebugDraw(1);

        return SdkSample::frameStarted(evt);

    }

exitPhysics()函数:

void exitPhysics()

    {

        delete dynamicsWorld;

        delete solver;

        delete dispatcher;

        delete collisionConfiguration;

        delete broadphase;

}

调用exitPhysics()函数:

void cleanupContent()

    {

        //clean up character controller and the floor mesh

        if (mChara)

        {

            mChara->exitPhysics();

            delete mChara;

            mChara = 0;

        }

        MeshManager::getSingleton().remove("floor", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

    }

 

 

调试物理世界函数:

DebugDraw.h

#ifndef DebugDrawer_h__

#define DebugDrawer_h__

 

//#include "../common.h"

#include "Ogre.h"_

#include "btBulletDynamicsCommon.h"

//#include "btShapeHull.h"

 

/** Ogre的三维向量转为bt的三维向量

 * @param V Ogre的三维向量

 * @return bt的三维向量

 */

inline btVector3 cvt(const Ogre::Vector3 &V){

    return btVector3(V.x, V.y, V.z);

}

 

/** bt的三维向量转为Ogre的三维向量

 * @param V bt的三维向量

 * @return Ogre的三维向量

 */

inline Ogre::Vector3 cvt(const btVector3&V){

    return Ogre::Vector3(V.x(), V.y(), V.z());

}

 

/** Ogre的四元数转为bt的四元数

 * @param Q Ogre的四元数

 * @return bt的四元数

 */

inline btQuaternion cvt(const Ogre::Quaternion &Q)

{

    return btQuaternion(Q.x, Q.y, Q.z, Q.w);

};

 

/** bt的四元数转为Ogre的四元数

 * @param Q bt的四元数

 * @return Ogre的四元数

 */

inline Ogre::Quaternion cvt(const btQuaternion &Q)

{

    return Ogre::Quaternion(Q.w(), Q.x(), Q.y(), Q.z());

};

 

 

 

 

class brPhysicsDebugDrawer: public btIDebugDraw,public Ogre::FrameListener

{

public:

  brPhysicsDebugDrawer( Ogre::SceneManager *scm);

  ~brPhysicsDebugDrawer();

 

  virtual void     drawLine (const btVector3 &from, const btVector3 &to, const btVector3 &color);

  virtual void     drawTriangle (const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar);

  virtual void     drawContactPoint (const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance,int lifeTime, const btVector3 &color);

  virtual void     reportErrorWarning (const char *warningString);

  virtual void     draw3dText (const btVector3 &location, const char *textString);

  virtual void     setDebugMode (int debugMode);

  virtual int     getDebugMode () const;

protected:

  bool frameStarted(constOgre::FrameEvent& evt);

  bool frameEnded(constOgre::FrameEvent& evt);

private:

  struct ContactPoint{

    Ogre::Vector3 from;

    Ogre::Vector3 to;

    Ogre::ColourValue   color;

    size_t        dieTime;

  };

  DebugDrawModes               mDebugModes;

  Ogre::ManualObject          *mLines;

  Ogre::ManualObject          *mTriangles;

  std::vector< ContactPoint >*mContactPoints;

  std::vector< ContactPoint >  mContactPoints1;

  std::vector< ContactPoint >  mContactPoints2;

};

 

#endif // DebugDrawer_h__

DebugDraw.cpp

#include "DebugDrawer.h"

//#include "OgreBulletUtils.h"

 

 

using namespace Ogre;

 

brPhysicsDebugDrawer::brPhysicsDebugDrawer( Ogre::SceneManager *scm )

{

  mContactPoints =&mContactPoints1;

  mLines = new ManualObject("physics lines");

  assert( mLines );

  mTriangles = new ManualObject("physicstriangles");

  assert( mTriangles );

  mLines->setDynamic(true);

 

  mTriangles->setDynamic(true);

  //mLines->estimateVertexCount(100000 );

  //mLines->estimateIndexCount(0 );

  Ogre::SceneNode*  node =scm->getRootSceneNode()->createChildSceneNode();

  node->attachObject( mLines );

  node->attachObject( mTriangles);

     //先隐藏

//   node->setVisible(false);

 

  static const char * matName = "OgreBulletCollisionsDebugDefault";

  MaterialPtr mtl =MaterialManager::getSingleton().getDefaultSettings()->clone(matName);

  mtl->setReceiveShadows(false);

  mtl->setSceneBlending( SBT_TRANSPARENT_ALPHA);

  mtl->setDepthBias( 0.1, 0 );

  TextureUnitState * tu = mtl->getTechnique(0)->getPass(0)->createTextureUnitState();

  assert( tu );

  tu->setColourOperationEx( LBX_SOURCE1,LBS_DIFFUSE );

  mtl->getTechnique(0)->setLightingEnabled(false);

  //mtl->getTechnique(0)->setSelfIllumination(ColourValue::White );

 

  mLines->begin( matName,RenderOperation::OT_LINE_LIST );

  mLines->position( Vector3::ZERO );

  mLines->colour( ColourValue::Blue );

  mLines->position( Vector3::ZERO );

  mLines->colour( ColourValue::Blue );

 

  mTriangles->begin( matName,RenderOperation::OT_TRIANGLE_LIST );

  mTriangles->position( Vector3::ZERO );

  mTriangles->colour( ColourValue::Blue );

  mTriangles->position( Vector3::ZERO );

  mTriangles->colour( ColourValue::Blue );

  mTriangles->position( Vector3::ZERO );

  mTriangles->colour( ColourValue::Blue );

 

  mDebugModes = (DebugDrawModes)DBG_DrawWireframe;

  Root::getSingleton().addFrameListener(this);

}

 

brPhysicsDebugDrawer::~brPhysicsDebugDrawer()

{

  Root::getSingleton().removeFrameListener(this);

  delete mLines;

  delete mTriangles;

}

 

void brPhysicsDebugDrawer::drawLine( const btVector3 &from, const btVector3 &to, const btVector3 &color )

{

  ColourValue c( color.getX(), color.getY(),color.getZ() ); 

  c.saturate();

  mLines->position( cvt(from) );

  mLines->colour( c );

  mLines->position( cvt(to) );

  mLines->colour( c );

}

 

void brPhysicsDebugDrawer::drawTriangle( const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar alpha )

{

  ColourValue c( color.getX(), color.getY(),color.getZ(), alpha ); 

  c.saturate();

  mTriangles->position( cvt(v0) );

  mTriangles->colour( c );

  mTriangles->position( cvt(v1) );

  mTriangles->colour( c );

  mTriangles->position( cvt(v2) );

  mTriangles->colour( c );

}

 

void brPhysicsDebugDrawer::drawContactPoint( const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance,int lifeTime, const btVector3 &color )

{

  mContactPoints->resize(mContactPoints->size() + 1 );

  ContactPoint p = mContactPoints->back();

  p.from = cvt( PointOnB );

  p.to = p.from + cvt( normalOnB ) * distance;

  p.dieTime =Root::getSingleton().getTimer()->getMilliseconds() + lifeTime;

  p.color.r = color.x();

  p.color.g = color.y();

  p.color.b = color.z();

}

 

bool brPhysicsDebugDrawer::frameStarted( const Ogre::FrameEvent& evt )

{

  size_t now =Root::getSingleton().getTimer()->getMilliseconds();

  std::vector< ContactPoint > *newCP =mContactPoints == &mContactPoints1 ? &mContactPoints2 : &mContactPoints1;

  for ( std::vector< ContactPoint >::iterator i =mContactPoints->begin(); i < mContactPoints->end(); i++ ){

    ContactPoint &cp = *i;

    mLines->position( cp.from );

    mLines->colour( cp.color );

    mLines->position( cp.to );

    if ( now <= cp.dieTime  )

      newCP->push_back( cp );

  }

  mContactPoints->clear();

  mContactPoints = newCP;

 

  mLines->end();

  mTriangles->end();

 

  return true;

}

 

bool brPhysicsDebugDrawer::frameEnded( const Ogre::FrameEvent& evt )

{

  mLines->beginUpdate(0);

  mTriangles->beginUpdate(0);

  return true;

}

 

void brPhysicsDebugDrawer::reportErrorWarning( const char *warningString )

{

 LogManager::getSingleton().getDefaultLog()->logMessage( warningString);

}

 

void brPhysicsDebugDrawer::draw3dText( const btVector3 &location, const char *textString )

{

 

}

 

void brPhysicsDebugDrawer::setDebugMode( int debugMode )

{

  mDebugModes = (DebugDrawModes) debugMode;

}

 

int brPhysicsDebugDrawer::getDebugMode() const

{

  return mDebugModes;

}

 

 

调用调试函数

 

brPhysicsDebugDrawer* m_pPhysicDebugDraw;

void physicsDebugDraw(int debugFlags)

    {

        if (dynamicsWorld&& dynamicsWorld->getDebugDrawer())

        {

            dynamicsWorld->getDebugDrawer()->setDebugMode(debugFlags);

            dynamicsWorld->debugDrawWorld();

        }

    }

    void draw(SceneManager*sceneMgr)

    {

        m_pPhysicDebugDraw = new brPhysicsDebugDrawer(sceneMgr);

       

        dynamicsWorld -> setDebugDrawer(m_pPhysicDebugDraw);

    }

在frameStarted函数中循环调用

  boolframeStarted(const FrameEvent& evt)

    {

        //let character update animations and camera

        mChara->addTime(evt.timeSinceLastFrame);

        mChara->frameStarted(evt);

        mChara->physicsDebugDraw(1);

        return SdkSample::frameStarted(evt);

    }