From Physics Simulation Wiki
Tutorial: Hello World Application
In this article we will show you how, in the most concise program possible, to initialise Bullet, set up a dynamics world, and allow a sphere to fall onto a surface. This is useful to verify that the build is working properly and also as a very top-level guide to using the Bullet API. First, we assume that Bullet is installed correctly and that the compiler is set up with the right Bullet include path (e.g. /usr/local/include/bullet) and is linking to the right libraries. Otherwise see Installation. If you're using gcc make sure you link to the static libraries in reverse order of dependency, i.e. your object files, dynamics, collision, math.
Full code is given at the bottom of the page
Start with a standard helloworld program:
Creating The World
Now, we will add a Bullet simulation. First, an appropriate include:
We want to instantiate a btDiscreteDynamicsWorld but to do this we need some other things too. For a "hello world" example they are cumbersome because we don't need them. However, as we mature our software into a useful product, they will be useful for fine-tuning the simulation.
We need to specify what Broadphase algorithm we want to use. Choosing the broadphase is important if the world will have a lot of rigid bodies in it, since it has to somehow check every pair which when implemented naively is an O(n^2) problem.
For alternative broadphase algorithms, see the Broadphase page.
The broadphase is an excellent place for eliminating object pairs that should not collide. This can be for performance or gameplay reasons. You can use the collision dispatcher to register a callback that filters overlapping broadphase proxies so that the collisions are not processed by the rest of the system. More information in Collision Things.
The collision configuration allows you to fine tune the algorithms used for the full (not broadphase) collision detection. Here be dragons!
We also need a "solver". This is what causes the objects to interact properly, taking into account gravity, game logic supplied forces, collisions, and hinge constraints. It does a good job as long as you don't push it to extremes, and is one of the bottlenecks in any high performance simulation. There are parallel versions available for some threading models.
Now, we can finally instantiate the dynamics world:
One last (rather obvious) line sets the gravity. We have chosen the Y axis to be "up".
Bullet has a policy of "whoever allocates, also deletes" memory, so all of these structures must be deleted at the end of main().
We now have prepared the first few lines that are common to *any* Bullet application. The code up to this point looks like this:
We will create a ground plane [a static rigid body], and a sphere that will fall onto the ground [a dynamic rigid body]. Each rigid body needs to reference a collision shape. The collision shape is for collisions only, and thus has no concept of mass, inertia, restitution, etc. If you have many bodies that use the same collision shape [eg every spaceship in your simulation is a 5-unit-radius sphere], it is good practice to have only one Bullet collision shape, and share it among all those bodies. However, we only have two rigid bodies and they are not the same shape so they will need a shape each.
In this demonstration, we will place a ground plane running through the origin. For pedantic purposes, we will define the collision shape with an offset of 1 unit from the origin. Later, we will place a rigid body using this shape in the world -1 unit away from the origin so the two offsets cancel and the plane winds up intersecting the origin. You could just use 0 for both values and achieve the same result, but here we place a plane defined by y = 1:
The shape that we will let fall from the sky is a sphere with a radius of 1 metre.
Collision shapes must be deleted at the end of the show just like everything else.
Now we can add the collision shapes into our scene, positioning them with rigid body instances.
Lets first instantiate the ground. Its orientation is the identity, Bullet quaternions are specified in x,y,z,w form. The position is 1 metre below the ground, which compensates the 1m offset we had to put into the shape itself. Motionstates are covered in detail on a page dedicated to them: MotionStates
The first and last parameters of the following constructor are the mass and inertia of the ground. Since the ground is static, we represent this by filling these values with zeros. Bullet considers passing a mass of zero equivalent to making a body with infinite mass - it is immovable.
Finally, we add the ground to the world:
Adding the falling sphere is very similar. We will place it 50m above the ground.
Since it's dynamic we will give it a mass of 1kg. I can't remember how to calculate the inertia of a sphere, but that doesn't matter because Bullet provides a utility function:
Now we can construct the rigid body just like before, and add it to the world:
A quick explanation of btRigidBody::btRigidBodyConstructionInfo is in order; when bodies are constructed, they are passed certain parameters. This is done through a special structure Bullet provides for this. The components of the btRigidBodyConstructionInfo are copied into the body when you construct it, and only used at initialisation time. If you want to create a thousand bodies with exactly the same properties, you only need to build one btRigidBodyConstructionInfo, and pass that same one to all the bodies that you create.
Stepping The Simulation
This is where the fun begins. We will step the simulation 300 times, at an interval of 60hz. This will give the sphere enough time to hit the ground under the influence of gravity. Each step, we will print out its height above the ground.
The stepSimulation function does what you'd expect, but its interface is fairly complicated. Read Stepping The World for more details.
After stepping, we examine the state of the falling sphere. The position and orientation are encapsulated in the btTransform object, which we extract from the falling sphere's motion state. We are only interested in the position, which we pull out of the transform with getOrigin(). We then print the y component of the position vector.
This should yield an output that looks like this:
Looks good so far. If you graph this output against the number of iterations, you get this:
The sphere comes to rest 1 metre above the ground. This is because the position is taken from the centre of the sphere and it has a radius of 1 metre. The sharp-eyed will note that the sphere penetrates the ground slightly before bouncing and coming to rest. This is to be expected in realtime physics engines, but it can be minimised by increasing the frequency of the simulation steps. Try it and see!
Now you can integrate the dynamics world into your application and render falling spheres. Check out the other Collision Shapes as well. Try stacking boxes or cylinders and then shooting them over with spheres.