Bullet3之封装PhysicsWorld3D
根据bullet3 HelloWorld程序去封装一个PhysicsWorld3D,
首先应该去创建一个物理世界,而对于一个物理世界,默认都有重力,提供一个创建
世界的静态方法(重力默认为(0, -10, 0))
- static PhysicsWorld3D* create(const btVector3& gravity = btVector3(0, -10, 0));
负责创建世界,同时对世界初始化
这里创建一个btDiscreteDynamicsWorld
直接复制bullet3 HelloWorld对世界的初始化,并修改
_collisionConfiguration,_dispatcher, _solver, _overlappingPairCache, _drawer均为成员变量,
具体使用参照Bullet的文档
- PhysicsWorld3D* PhysicsWorld3D::create(const btVector3& gravity)
- {
- auto world = new PhysicsWorld3D;
- if (world && world->initWorld(gravity))
- {
- return world;
- }
- delete world;
- return nullptr;
- }
- bool PhysicsWorld3D::initWorld(const btVector3& gravity)
- {
- _collisionConfiguration = new btDefaultCollisionConfiguration();
- _dispatcher = new btCollisionDispatcher(_collisionConfiguration);
- _overlappingPairCache = new btDbvtBroadphase();
- _solver = new btSequentialImpulseConstraintSolver;
- _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
- if (_world == nullptr)
- {
- return false;
- }
- _world->setGravity(gravity);
- return true;
- }
销毁一个物理世界
- void PhysicsWorld3D::destroy()
- {
- this->clear();
- delete _collisionConfiguration;
- delete _dispatcher;
- delete _solver;
- delete _overlappingPairCache;
- delete _world;
- delete this;
- }
- void PhysicsWorld3D::clear()
- {
- int i;
- //remove the rigidbodies from the dynamics world and delete them
- for (i = _world->getNumCollisionObjects() - 1; i >= 0; i--)
- {
- btCollisionObject* obj = _world->getCollisionObjectArray()[i];
- btRigidBody* body = btRigidBody::upcast(obj);
- if (body && body->getMotionState())
- {
- delete body->getMotionState();
- delete body->getCollisionShape();
- }
- _world->removeCollisionObject(body);
- delete obj;
- }
- }
创建一些简单的body
由于每种body都有自己的材质信息
btRigidBodyConstructionInfo是构造一个刚体信息的结构体,
我们只需关心几个参数,
friction; // 摩擦系数
rollingFriction; // 滚动摩擦系数
restitution; // 恢复系数(弹性系数)
mass; // 质量
自己去实现一个简单的材质结构体
- struct PhysicsMaterial3D
- {
- btScalar friction;
- btScalar rollingFriction;
- btScalar restitution;
- btScalar mass;
- PhysicsMaterial3D() :
- friction(0.0f),
- rollingFriction(0.f),
- restitution(0.f),
- mass(0.f)
- {}
- PhysicsMaterial3D(btScalar aMass, btScalar aFriction, btScalar aRestitution, btScalar aRollingFriction) :
- friction(aFriction),
- rollingFriction(aRollingFriction),
- restitution(aRestitution),
- mass(aMass)
- {}
- };
并提供一个默认的材质信息
- const PhysicsMaterial3D PHYSICS_MATERIAL3D_DEFAULT(1.f, 0.5f, 0.5f, 0.0f);
实现构造3个基本物体,如下声明
- btRigidBody* addPlane(const btVector3& normal, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
- btRigidBody* addSphere(btScalar radius, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
- btRigidBody* addBox(const btVector3& halfSize, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
对于一个无限的平面,需要一个法向量决定Plane的朝向,同时position决定plane的位置,当然还有材质,但是mass必须为0
对于一个球体(Sphere)半径,位置,材质
对于一个盒子(Box)尺寸, 位置,材质
- btRigidBody* PhysicsWorld3D::addPlane(const btVector3& normal, const btVector3& position, const PhysicsMaterial3D& material)
- {
- CCAssert(material.mass == 0.f, "plane's mass must be 0."); // 特殊处理,保证mass为0
- btCollisionShape* groundShape = new btStaticPlaneShape(normal, 0.f);
- auto body = getBody(groundShape, position, material);
- _world->addRigidBody(body);
- return body;
- }
- btRigidBody* PhysicsWorld3D::addSphere(btScalar radius, const btVector3& position, const PhysicsMaterial3D& material)
- {
- btCollisionShape* colShape = new btSphereShape(radius);
- auto body = getBody(colShape, position, material);
- _world->addRigidBody(body);
- return body;
- }
- btRigidBody* PhysicsWorld3D::addBox(const btVector3& size, const btVector3& position, const PhysicsMaterial3D& material)
- {
- btCollisionShape* colShape = new btBoxShape(size * 0.5f); // halfSize
- auto body = getBody(colShape, position, material);
- _world->addRigidBody(body);
- return body;
- }
构造一个刚体包含一些共同的步骤collisionShape, position, material
由于Plane,Sphere,Box collisionShape类型不同,所以单独实现,
其他的公共步骤可以抽离出来
- btRigidBody* getBody(btCollisionShape* colShape, const btVector3& position, const PhysicsMaterial3D& material);
仿照HelloWorld构造body的方法
- btRigidBody* PhysicsWorld3D::getBody(btCollisionShape* colShape, const btVector3& position, const PhysicsMaterial3D& material)
- {
- /// Create Dynamic Objects
- btTransform startTransform;
- startTransform.setIdentity();
- //rigidbody is dynamic if and only if mass is non zero, otherwise static
- bool isDynamic = (material.mass != 0.f);
- btVector3 localInertia(0,0,0);
- if (isDynamic)
- colShape->calculateLocalInertia(material.mass, localInertia); // 计算物体惯性
- startTransform.setOrigin(position); // 设置物体位置
- //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
- btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
- btRigidBody::btRigidBodyConstructionInfo rbInfo(material.mass, myMotionState,colShape,localInertia);
- // 使用自定义的材质
- rbInfo.m_restitution = material.restitution;
- rbInfo.m_friction = material.friction;
- rbInfo.m_rollingFriction = material.rollingFriction;
- // 创建body
- btRigidBody* body = new btRigidBody(rbInfo);
- return body;
- }
不要忘了物理世界的更新
- void PhysicsWorld3D::update(float dt)
- {
- _world->stepSimulation(dt);
- }