Bullet is a popular 3d physics engine used in many open source and commercial products, including Ogre and Blender.
The API can be downloaded here.
There is a user's guide on the Bullet site, as well as a Wiki. There is also an extensive collection of demos included with the source. Bullet makes uses of the Cross-Platform make build system.
Bullet allows you to create a world with objects that have properties like position, mass, linear velocity, and angular velocity. It has advanced collision detection algorithms that handle realistic transfer of force and updating of object positions. These computations exist separately from any graphical objects, so you are responsible for draw your world based on information stored in Bullet objects.
For example, there is a btDiscreteDynamicsWorld object. There are different collision detection algorithms, settings for gravity, etc and we can define these on the world object. Some of these algorithms have GPU implementations that the world can use if desired. Here's one example of setting up a world.
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(); btCollisionDispatcher* collisionDispatcher = new btCollisionDispatcher(collisionConfiguration); btBroadphaseInterface* pairCache = new btDbvtBroadphase(); btSequentialImpulseConstraintSolver* constraintSolver = new btSequentialImpulseConstraintSolver(); // world is a member variable of the Vrong class, a simple ping pong app world = new btDiscreteDynamicsWorld(collisionDispatcher, pairCache, constraintSolver, collisionConfiguration); world->setGravity(btVector3(0, 0, -2));
We then add objects to the world.
btCollisionShape* ballShape = new btSphereShape(ballRadius); btRigidBody* ballBody = addBody(1.0, ballShape, btVector3(0, 0, 0), 0.9);
Here's small helper function called addbody to handle some boilerplate:
btRigidBody* Vrong::addBody(float mass, btCollisionShape* shape, btVector3 origin, float restitution, float friction) { // motion btTransform t; t.setIdentity(); t.setOrigin(origin); btDefaultMotionState* motion = new btDefaultMotionState(t); // body btRigidBody* body = new btRigidBody(mass, motion, shape); body->setRestitution(restitution); body->setFriction(friction); world->addRigidBody(body); return body; }
Here's the display function for drawing the ball:
void Vrong::display(GLContextData& contextData) const { DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this); // draw objects glMaterial(GLMaterialEnums::FRONT_AND_BACK, *dataItem->ballMaterial); drawSphere(ballBody); }
Drawing the sphere is simple:
void drawSphere(btRigidBody* body) { btTransform t; body->getMotionState()->getWorldTransform(t); btVector3 p = t.getOrigin(); glPushMatrix(); glTranslatef(p[0], p[1], p[2]); glDrawSphereMercator(1, 20, 20); glPopMatrix(); }
Finally, here's our frame function:
void Vrong::frame() { world->stepSimulation(1/60.0, 10); Vrui::requestUpdate(); }
For more info, check the Wiki and the bundled demos.