I have decided to wrap up my quick series about the Bullet Physics engine for now. Later I hope to cover raycast (we’re using that to test whether a NPC can see the PC in our coming game), constraints and soft bodies.
The survival kit includes the following articles:
Remember these are working notes. I still recommend you look at the official tutorials on the Bullet website – they are definitely more comprehensive.
We’re getting good results with Bullet so far and we feel really happy that I bothered building an integration for it. Our integration uses Objective C++ and provides a wrapper that can be used from Objective C. Here are some reasons we feel happy:
Getting notified when a collision occurs is very useful:
Bullet uses the following concepts to handle collisions and contact:
After iterating the simulation, we can retrieve contact pairs and check the number of contact points. So we can tell whether two objects collided (contact points > 0) or lost contact (contact points == 0)
Colliding objects are returned as instances of btCollisionObject (which btRigidBody inherits from). The method used to return collision pairs (aka manifolds) can return a pair with zero contact points. Just because we have a pair doesn’t mean there’s a collision, or contact.
The following code fragment may be called after stepSimulation().
__________________________
int numManifolds = world->getDispatcher()->getNumManifolds();
for (int i=0;i<numManifolds;i++){
btPersistentManifold* contactManifold =
world->getDispatcher()->getManifoldByIndexInternal(i);
btCollisionObject* obA =
static_cast<btCollisionObject*>(contactManifold->getBody0());
btCollisionObject* obB =
static_cast<btCollisionObject*>(contactManifold->getBody1());
int numContacts = contactManifold->getNumContacts();
}
_________________________
You can also find information about the location of contact points. Check the Bullet Wiki tutorials for more information about collisions and collision filtering
Impact velocity
I find that impact velocity can be reliably retrieved right when the bodies collide – in the code fragment above, obA, obB thus store their velocity at the time of impact, right before applying restitution. This is convenient to evaluate damage (e.g. remove health points / apply a stunning effect etc… ) resulting from collisions.
Most 3D applications use a scenegraph that stores scene node coordinates and we need a convenient way to update these coordinates from the physical simulation. In this case the simulation contains a dynamic object which moves ‘on its own’, being subject to gravity, collisions and other forces.
Often we want to animate objects ourselves, but we still want other objects to bounce off such objects, so we create a kind of alias or reference to the object we’re animating. Such an alias or reference is made into a kinematic object. A kinematic object still has physical properties (e.g. friction) that help determine how dynamic objects interact with it.
This article is a work in progress. Please refer to the motion state tutorial on the Bullet wiki. In theory motion states and kinematic bodies are ‘pretty simple’. I often find it easier to use dynamic bodies out of the box and rely on the default motion state.
The motion state
All bodies in the simulation are setup with a motion state.
The motion state allows sharing a node’s transform between the physics engine and the renderer. btMotionState is a small interface that specifies a getter/setter pair. The bullet API calls the getter to retrieve the shared transform and calls the setter to assign it.
Kinematic objects aren’t animated by the simulation, ‘we do it ourselves’. How do we let the simulation know that these objects have moved?
Configuration:
There are two steps to ‘make an object kinematic’.
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
This flag tells the engine that the object is kinematic – so it shouldn’t move under the influence of gravity or because of colliding with other objects.
body->setActivationState(DISABLE_DEACTIVATION);
This prevents the object from ‘falling asleep’. Normally objects that haven’t moved in a while aren’t processed and keep sleeping until something bumps into them, or something that they’re in contact with wakes them up. Since kinematic objects aren’t affected by forces, we need to prevent them from falling asleep.
Back to dynamic state (UNTESTED)
body->setCollisionFlags( body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT));
body->activate(true); // or try… body->forceActivationState(ACTIVE_FLAG)
Tips and Caveats
Today I’m covering simple methods used to move dynamic objects. I am also introducing servo-controllers.
To study the effect of forces on an object’s velocity and position, it is good to know how to step the simulation correctly. Before reading this tutorial, you may wish to have a look on the bullet wiki and read stepping the world.
Additionally, you may want to check the btRigid body class reference on the Bullet site. btRigidBody provides other methods that can be used to apply torques and forces.
Forces
You can apply forces using:
btRigidBody::applyCentralForce(btVector3 F)
If you call this method, a force equal to F*t will be applied at the next frame, where:
When using applyCentralForce, the total force applied depends on the duration of the next frame.
Example 1:
float duration = 0.5f; // frame duration (seconds)
float maxSubsteps = 5; // max number of substeps to update
float tick = 0.1f; // max duration of a substep (seconds)
body->applyCentralForce(btVector3(1,0,0));
world->step(duration,maxSubsteps,tick); // total force applied: 0.5N
Example 2:
float duration = 0.2f;
float maxSubsteps = 5;
float tick = 0.1f;
body->applyCentralForce(btVector3(1,0,0));
world->step(duration,maxSubsteps,tick); // total force applied: 0.2N
Impulses
If you want to give a one-off ‘impulse’ irrespective of frame duration, you can use:
btRigidBody::applyCentralImpulse(btVector3 F)
In this case the total force applied at the next frame is F, irrespective of frame duration.
Continuous forces
If you want to apply continuous forces (e.g, traction generated by an engine), you should call applyCentralForce at every frame. This is because forces are reset after the next frame:
body->applyCentralForce(btVector3(1,0,0));
world->step(0.1f,10,0.02f); // applied 0.1 N
world->step(0.1f,10,0.02f); // applied 0.0 N
High-school memory: Just because forces are reset doesn’t mean the object will stop moving right away! If there is no air resistance or friction, the body will continue moving forever.
How do I control the object’s velocity?
When dealing with forces, you can adjust forces using a servo-controller (aka servo-mechanism or servo). A servo uses negative feedback to adjust it’s input in order to regulate it’s output.
Why can’t I just set the velocity directly?
If you want a dynamic object that collides, falls under the effect of gravity and rests on the ground automagically, setting velocity directly isn’t a good idea (you’ll end up canceling the effect of all these forces). Instead you want to set the target velocity and let a servo generate forces to adjust your object’s velocity.
OK, how do I write a servo? Is it hard?
A basic servo works like this:
Use btRigidBody:getLinearVelocity() to read a body’s current velocity.
The tricky part is getting the scale factor right. As a rule of the thumb if you try with a 1kg sphere, a factor between 10 and 50 works fine. A smart servo adjusts the scale factor automatically.
I will provide sample code for servos another time. We have enough on our hands learning Bullet.
In the Bullet Physics Library, collision shapes are used to detect collisions between physical bodies.
You can get a feel of what’s available by looking at the inheritance diagram (from the Bullet docs). Depending on the workflow you’re implementing, just using meshes may be a quick-fix. However meshes have several disadvantages, which is why geometric primitives are thrown in:
Convex/Concave
Convex shapes tend to process collisions faster:
Concave shapes tend to process collisions slower
If your mesh is convex (boulder?) or mainly interacts with objects 5-10 times bigger than itself, btConvexPointCloudShape has better performance than btBvhTriangleMeshShape.
If we model a coffee cup using a convex point cloud, we can’t shoot a bullet through the handle(*). But there’s no effective difference when simulating a cup falling on the ground (either way it won’t shatter like the real one, which is sad).
(*) got this example from Wikipedia
Code samples
Collision mesh
To create a collision mesh, we can use…
Example:
#include “btBulletDynamicsCommon.h”
// … DIY: put this code in a function or class method…
btTriangleMesh* data = new btTriangleMesh();
btVector3 A(0.0f,0.0f,0.0f);
btVector3 B(1.0f,0.0f,0.0f);
btVector3 C(0.0f,0.0f,1.0f);
data->addTriangle(A,B,C,false); // false, don’t remove duplicate vertices
// true for using quantization; true for building the BVH
btBvhTriangleMeshShape* shape=new btBvhTriangleMeshShape(data,true,true);
The flags (quantization, BVH) have to do with internal optimizations, I just use the recommended defaults.
Note: I once idiotically created degenerate meshes (each triangle used 3 times the same point). A mesh setup in this awful way may sometimes generate collisions and cause fancy restitution effects. Before you start looking everywhere else for ways to fix tunneling and restitution, make sure your mesh is correctly setup (sigh).
Sphere
float radius=2.5f;
btCollisionShape* shape = new btSphereShape(radius);
Capsule
float totalHeight=5.0f;
float radius=1.0f;
btCollisionShape* shape = new btCapsuleShape(radius,totalHeight-radius*2.0f);
A capsule looks like a medicine pill standing upright. You can use btCapsuleShapeX / btCapsuleShapeZ if you want a different orientation. You could also use btMultiSphereShape if you want to create ‘thick segments’ with round caps (without using a transform) or other interesting things (rounded cuboids and such…)
Workflow notes
If you don’t want your setup to be completely game/application specific, simple techniques can be used to select the right primitives.
In my 3D editor, I use layers to hold various kinds of objects. So I have a layer for actors, another for the terrain, etc…
Instead of, or in combination with layers, you can use reference metrics to help you decide how an object should be represented:
‘Reference metrics’ means that you pass a descriptor defining ‘large, medium, small and fast’ to the class that builds your collision shapes. Then we can use the same factory over and over with game specific metrics. If you simulate very large or very small objects (‘not human scale’), you should worry about scaling (link to the Bullet wiki).
Next time…
Gravity’s fun. Applying forces and shoving bodies around is more fun. Next time we’ll look into dynamic and kinematic behavior.
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:
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:
I’m totally against option 1.
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:
Last time I documented a rough setup for Bullet on iOS. I think this is much cleaner and would highly recommend you try it. It should take no more than an hour. If you have problems with this, please drop a comment and I’ll try to help you out.
Recipe for building bullet as an iOS ready static library
Why do it this way?
There are several assumptions underlying this approach:
Is there a better way to do it?
I guess if you have the right make file or know how to create one and are willing to spend the time, maybe it would be better. Especially if it can automatically detect changes when you update to a more recent version of the library.
A few caveats