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!

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2011-2022 仙雾

请我喝杯咖啡吧~

支付宝
微信