Bullet物理引擎学习笔记1
Bullet物理引擎学习笔记1
仙雾折腾了两天,各种乱七八糟blog还有wiki什么的翻了个遍,从零开始学就是这样的,痛并快乐着。
我是用的是bullet-2.77,因为googlecode上这个版本有编译好的demo,我可以先下下来看,编译的过程很简单,vs打开工程生成一下就行了,不过这里有可能会报个小小的error,转到出错的位置后,只要将PostBuild那个target全注释掉就行了。
一开始我在用不用OgreBullet这个开源项目上纠结了半天,最后我放弃了它,现在想想还是正确的,OgreBullet是一个封装好的项目,实际上不利于像我这样从头开始学习Bullet的人。
由于项目的目的是要做一个躲避球的游戏,我初步的设想就是写一个能控制物体去躲避物体的demo,这里我选用了最简单的物体,也就是bullet里的基本Shape之一的盒子(box)。
要完成这个目标,我计划分步学习实现。
首先让bullet能和ogre结合起来,即能够通过物理引擎的计算将物体的正确位置显示到界面上,能够创建并发射一系列的盒子。
其次,能够检测出盒子的碰撞,并将于指定物体碰撞的盒子进行删除。
然后,能通过鼠标或键盘来控制指定物体进行躲避。
最后,能同过Kinect来控制物体。
其中,前3步不需要Kinect的辅助,可以先完成。做完这些后,就是对游戏的润化和调优,以后再说。
先说第一步吧,首先我们需要在ogre的世界和bullet的物理世界中创建物体,在这之前,我们需要对bullet的世界进行初始化。(不要问我这些是什么意思,我自己也似懂非懂的)
btDiscreteDynamicsWorld* m_dynamicsWorld; btDefaultCollisionConfiguration* m_collisionConfiguration; btCollisionDispatcher* m_dispatcher; btBroadphaseInterface* m_overlappingPairCache; btSequentialImpulseConstraintSolver* m_solver; btAlignedObjectArray m_collisionShapes;
void initPhysics()
{
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_overlappingPairCache = new btDbvtBroadphase();
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
m_solver = sol;
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_overlappingPairCache, m_solver, m_collisionConfiguration);
m_dynamicsWorld->setGravity(btVector3(0, -10, 0));
}
接下来开始创建物体,NodeInfo是我自己设置的一个类,记录了Ogre中的SceneNode和一些其他信息。
//in physics btCollisionShape* boxShape = new btBoxShape(btVector3(size.x,size.y,size.z));//创建Shape float mass = 1.f;//质量,这里要说明的是,如果质量是0的话表示是一个静态物体或者Kinematic物体(不知道怎么翻译),区别可以看UserManual btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,5,0));//设置位置 bool isDynamic = (mass != 0.f); btVector3 localInertia(0,0,0); if (isDynamic) boxShape->calculateLocalInertia(mass,localInertia);//不知道干什么的 btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);//创建一个MotionState以后会用到 btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,boxShape,localInertia); btRigidBody* boxBody = new btRigidBody(cInfo);//创建它 NodeInfo *nodeInfo = new NodeInfo(node, "KinematicBodyBox", "man"); boxBody->setUserPointer((void*)nodeInfo);//通过bullet预留的一个指针,记录Ogre中对应node的信息,以便更新位置 m_dynamicsWorld->addRigidBody(boxBody);
bullet通过下面这句话进行模拟,后面的参数是模拟多少时间。
m_dynamicsWorld->stepSimulation(etime);
之后我们可以对node的位置等进行更新
btCollisionObjectArray bodies = m_dynamicsWorld->getCollisionObjectArray(); btRigidBody *TObject; for (int i=0;i(TObject->getUserPointer()); if (TObject->isStaticOrKinematicObject()) { continue; }
// Set position
btVector3 Point = TObject->getCenterOfMassPosition();
nodeInfo->node->setPosition(Ogre::Vector3(Point.getX(), Point.getY(), Point.getZ()));
// Convert the bullet Quaternion to an Ogre quaternion
btQuaternion btq = TObject->getOrientation();
Ogre::Quaternion quart = Ogre::Quaternion(btq.w(),btq.x(),btq.y(),btq.z());
// use the quaternion with setOrientation
nodeInfo->node->setOrientation(quart);
}
你可以将一个物体的初始高度设为100,然后在每次stepSimulation后输出其高度,可以看到它会落入无底深渊。。。你也可以创建一个平面,阻止其下落。
//in physics btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),0); btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0))); btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0)); btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI); m_dynamicsWorld->addRigidBody(groundRigidBody, COL_GROUND, groundCollidesWith);
最后你可以通过Ogre的FrameListener实现按一下键盘的某个键,就发射一个盒子。
Enjoy yourself in Bullet!