Bullet Basic Example 示例

代码参见:bullet3/examples/BasicDemo


在 Bullet 自带的例程中,仿真主要包括以下三步:

(1)example->initPhysics();
首先,初始化仿真相关的环境。建立仿真相关对象,添加场景中的物体,等等。

(2)example->stepSimulation(1.f / 60.f);
执行仿真步骤。

(3)example->exitPhysics();
最后,清理仿真相关的对象。


(0)仿真场景相关的类极其组成

在仿真场景中,主要涉及到的类有:

btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
btBroadphaseInterface* m_broadphase;
btCollisionDispatcher* m_dispatcher;
btConstraintSolver* m_solver;
btDefaultCollisionConfiguration* m_collisionConfiguration;
btDiscreteDynamicsWorld* m_dynamicsWorld;

(1)初始化仿真环境
所谓初始化仿真环境,一方面需要建立仿真场景相关的类,另一方面需要向仿真场景中添加所需要的物体。比如,在 BasicExample::initPhysics() 中,首先需要建立空的 EmptyDynamicWord ,即:

///collision configuration contains default setup for memory, collision setup
m_collisionConfiguration = new btDefaultCollisionConfiguration();
//m_collisionConfiguration->setConvexConvexMultipointIterations();

///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);

m_broadphase = new btDbvtBroadphase();

///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
m_solver = sol;

m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);

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

接下来,需要这个 EmptyDynamicWord 中添加物体,即

///create a few basic rigid bodies
btBoxShape* groundShape = createBoxShape(btVector3(btScalar(50.), btScalar(50.), btScalar(50.)));

//groundShape->initializePolyhedralFeatures();
//btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50);

m_collisionShapes.push_back(groundShape);

btTransform groundTransform;
groundTransform.setIdentity();
groundTransform.setOrigin(btVector3(0, -50, 0));

{
	btScalar mass(0.);
	createRigidBody(mass, groundTransform, groundShape, btVector4(0, 0, 1, 1));
}

其中, createRigidBody(...) 的内容为:

btVector3 localInertia(0, 0, 0);
if (isDynamic)
	shape->calculateLocalInertia(mass, localInertia);

//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects

btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);

btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);

btRigidBody* body = new btRigidBody(cInfo);
//body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);


body->setUserIndex(-1);
m_dynamicsWorld->addRigidBody(body);

(2)执行仿真步骤

这个就比较清晰了,可以认为是一个大的步骤 m_dynamicsWorld->stepSimulation(deltaTime);

(3)结束仿真并清理仿真场景

大致就是清理各种 new 出来的对象,这里就不再赘述了。


通过这个简单的示例,Bullet 总的框架就比较清晰了。可以认为,通过 btDiscreteDynamicsWorld 类创建了一个空的仿真场景。向场景中添加物体、以及物体之间的约束(比如关节等),再由 btDiscreteDynamicsWorld::stepSimulation(t) 进行仿真计算。

那么,这里就需要进一步弄清楚两个问题,(1)仿真场景中相关的类是什么样的构成,比如物体类 btBoxShape 、碰撞对象类 btCollisionShape 、以及碰撞检测类 btCollisionDispatcher btBroadphaseInterface btDefaultCollisionConfiguration 、约束类 btTypedConstraint btConstraintSolver、等等是怎样构成的;(2)仿真步骤是如何一步一步执行的,即 btDiscreteDynamicsWorld::stepSimulation(t) 里面包含了怎样一步一步的小步骤。

posted @ 2020-04-30 23:42  wghou09  阅读(689)  评论(0编辑  收藏  举报