The Bullet Physics Library is an open source (free for private and commercial use) physics engine mainly written by Erwin Coumans. After 8 years of development or more, it is a mature library. Integrations with Ogre, Irrlicht, Unity and other engines are available. It also integrates with content creation software, including Maya and Blender and has been used in a lot of games (wikipedia?)
After messing with the build a little (see my recent posts), we are ready for a friendly introduction.
How simple is simple?
Conceptually, this is how I want to setup a physics simulation:
- Create a container (‘physics world’).
- Add objects, aka ‘rigid bodies’.
- Step the simulation and enjoy the result.
That would be 3 lines of code, right? How about something like…
PhysicalWorld world=new PhysicalWorld();
world.addBody(new Ball());
for(int i=0;i<10;i++)world.step(10); // 10 milliseconds
There are countless assumptions underlying this code. Gravity. Friction. Flying cows. You name it. I’m not saying that a physics engine should provide this level of integration (who would ever need it?); definitely not saying that there shouldn’t be 3 or 4 additional constructors taking in quizzical parameters.
I know this: if a physics engine’s hello world program looked like this, countless school kids would try it out, feel an atavistic surge of adrenaline and dive into the gory details.
You won’t get away without reading the bullet hello world tutorial
Let’s see how Bullet lives up to the leap of faith. I simplified their hello world tutorial for you, but frankly I’m just trying to encourage you to read it. I also highlighted the key steps.
#include <btBulletDynamicsCommon.h>
int main (void){
// create the 'physical world'
//
btBroadphaseInterface* broadphase =
new btDbvtBroadphase();
btDefaultCollisionConfiguration* collisionConfiguration =
new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher =
new btCollisionDispatcher(collisionConfiguration);
btSequentialImpulseConstraintSolver* solver =
new btSequentialImpulseConstraintSolver;
btDiscreteDynamicsWorld* dynamicsWorld =
new btDiscreteDynamicsWorld(
dispatcher,broadphase,solver,collisionConfiguration);
dynamicsWorld->setGravity(btVector3(0,-10,0));
// create the ball
//
btCollisionShape* shape = new btSphereShape(1);
btDefaultMotionState* motionState =
new btDefaultMotionState(
btTransform(btQuaternion(0,0,0,1),
btVector3(0,50,0))
);
btScalar mass = 1;
btVector3 inertia(0,0,0);
shape->calculateLocalInertia(mass,inertia);
btRigidBody::btRigidBodyConstructionInfo
bodyDescriptor(mass,motionState,shape,inertia);
btRigidBody* ball = new btRigidBody(bodyDescriptor);
dynamicsWorld->addRigidBody(ball);
// step the simulation (and enjoy the result)
//
for (int i=0 ; i<10 ; i++){
dynamicsWorld->stepSimulation(1/60.0f,10);
}
// remove and delete the ball
//
dynamicsWorld->removeRigidBody(ball);
delete ball->getMotionState();
delete ball;
delete shape;
// delete the world
//
delete dynamicsWorld;
delete solver;
delete collisionConfiguration;
delete dispatcher;
delete broadphase;
return 0;
}
Not self explanatory
To avoid plagiarism and rest my keyboard, I suggest you go and read that tutorial. It explains everything step by step. Aside, the original tutorial includes a ground plane and log output so you can ‘see the ball falling and bouncing’ (that is, read the log and observe that the height of the ball varies).
Seeing is believing. Testing is learning.
After pasting in the original tutorial, we have a choice:
- Plug graphic output of sorts and start hacking way
- Read on, write sample code and verify our assumptions using tests.
I’m totally against option 1.
- If you haven’t got a system that produces graphic output yet, trying out everything at once will bring utter confusion.
- If you do have a system that produces graphic output and attempt integrating right away, you’re burdening yourself with the need to match your transforms and rotations to bullet’s before learning anything physics related, which is somewhat demotivating; or…
- …you are blissfully ignoring the fact that with screwed up transforms, the physics will appear to go awfully wrong. Then you’ll be asking around, complaining and imagining bugs that aren’t there.
Option 2 consists in getting a test framework up and running and writing innocuous simulations using the hello world tutorial as a starting point. Use console output; assert results; use breakpoints.
You can test without a test framework but you’ll end up with a mess of ‘little tests’ that only run when you ask them to. Lining up tests using a test framework is cleaner, faster and documents our learning process.
Outlook
This article is retrospective. I’m integrating bullet with my game engine and hope to get ‘all basic stuff’ sorted this weekend. Seven rough days in, I can build a ‘physics world’ that matches my game scenes, got the transforms sorted and can mix dynamic and kinematic objects.
In the next articles I will cover the following:
- collision and contact
- dynamics and kinematics (aka ‘the motion state’)
- creating meshes and other objects
- transforms and rendering.