一、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截图:
四、具体实现代码
定义的几个类,作为参数传入建立动态物理世界
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<