Skip to content

Archive

Category: Game Programming

This post is password protected. To view it please enter your password below:


This post is password protected. To view it please enter your password below:


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:

  1. Integrating bullet with our engine has been fairly smooth. There is a learning curve (and I’m still learning!) but the APIs are often fairly explicit and the library is kind of easy to use.
  2. Having a nice physics engine take care of collisions and moving objects around just saves a lot of work. Game dev folklore claims that non-physics oriented games won’t take advantage of a physics engine. Think again?
  3. Objective C is not very fast. Bullet provides many optimizations that we couldn’t afford coding ourselves – and it’s all C++.

Getting notified when a collision occurs is very useful:

  • Did a projectile or weapon score a hit?
  • Did an actor enter an active area?
  • Did an actor start falling?

Bullet uses the following concepts to handle collisions and contact:

  • Contact Pair: two objects that may collide form a contact pair. This contact pair exists even if there is no collision. Here a synonym for contact pair is ‘manifold’.
  • Contact Points: at any time two objects may have zero, one or more contact points.

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?

  1. Create a rigid body that will ‘stand for’ the kinematic object. This will be a kind of ‘alias’ or ‘reference’ to the object we’re animating, so we need to disable dynamics for this object (so it won’t be influenced by gravity or other objects).
  2. implement getWorldTransform() so that an up to date transform is returned whenever the simulation calls that function.
  3. Implement setWorldTransform() so that you (or the engine, if interpolating) can set the transform.
  4. Make the object ‘kinematic’ (see below)

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

  • Avoid relying on how many times or when the motion state’s get/set methods are accessed. Even if your object is not kinematic, the motion state’s getter may be called after the initial simulation step (TESTED).
  • If you ‘teleport’ a dynamic object, set the object’s transform by calling body->getWorldTransform().setOrigin(); even if you have removed the body from the simulation, after adding this object again the transform underlying your motion state may be overridden by a call to setWorldTransform before getWorldTransform is called by the engine.
  • In my experience it would appear that kinematic objects are somewhat less reliable than dynamic objects. I often seen tunneling effects that disappear if I use a dynamic object instead. Once again testing in a sandbox can be very helpful in such cases.

This post is password protected. To view it please enter your password below:


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:

  • F is expressed in Newtons per second.
  • t is the duration of the next ‘physics frame’.

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:

  1. Assume a target velocity v0
  2. Read the current velocity v
  3. Evaluate the error: e = v – v0
  4. Evaluate a correction factor: c = – e = v0 – v
  5. Apply the correction factor multiplied by an arbitrary scale factor k:
    F = k . ( v0 – v )

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:

  • Performance – colliding meshes can be slow
  • Reliability – high speed objects are more likely to miss/fall through when colliding with meshes. This can be fixed using ‘continuous collision detection’ or stepping the simulation slower, but it may reduce performance even more.
  • Memory – Primitives use very little memory.

Convex/Concave

Convex shapes tend to process collisions faster:

  • cone, capsule, sphere, box, cylinder …

Concave shapes tend to process collisions slower

  • Banana, bowl, ring, coffee cup…

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…

  • If you don’t need much realism, capsules are a popular choice for actors (another time, I’ll explain why I prefer using spheres).
  • boxes or spheres may be a good choice if you want to include collectible items in your simulation.

Instead of, or in combination with layers, you can use reference metrics to help you decide how an object should be represented:

  • large, concave objects (e.g, weird shaped platforms and such) may require ad-hoc meshes with as few triangles as possible (use a triangle mesh)
  • medium sized objects may use convex point clouds.
  • small objects can use box, cylinder or sphere primitives. If you don’t want your objects to roll, boxes and cylinders are a better choice.
  • fast, small objects (projectiles) can miss collisions easily. Using an elongated ‘dash-arrow-shaped-thing’ (triangle or cylinder) eliminates this problem.

‘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:

  1. Create a container (‘physics world’).
  2. Add objects, aka ‘rigid bodies’.
  3. 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:

  1. Plug graphic output of sorts and start hacking way
  2. 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.

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

  1. Grab the archive. I used the *.tgz version (=> download page; Bullet physics engine homepage)
  2. Extract this somewhere you like; I put this under trunk/ext/bullet, thus renaming from bullet-x.xx to bullet
  3. Go to bullet/Extras/AllBulletDemosOSX; find a project named AllBulletDemos.xcodeproj
  4. Drag the project in your xcode workspace (requires XCode 4 or later). At the time of writing the OS X demos build correctly with XCode  4.0.2. Note that this is a MacOS project, not an iOS project – if you build and run you should see a window with lots of attractive demos. If you don’t see this window try to fix the project first(!).
  5. Create a new project (static library) in the same workspace. If you create this project inside the bullet folder, you could name it ios, then rename the project to bullet. You may let XCode create a unit tests target for you.
  6. Use the project navigator to find a group under AllBulletDemosOSX/src/src. Drag this group to the newly created bullet project.
  7. At project level in build settings, set the header search path to ../src and check ‘recursive’
  8. build.
  9. At this point you can remove AllBulletDemosOSX from your workspace if you wish.
  10. (strongly recommended) use the ‘hello world’ code from the bullet wiki to write a simple test, and make sure you get the test to build and run correctly. You probably need to add files that were not under AllBulletDemosOSX/src/src. This is likely to happen because there is no automation that reliably tells xcode to include new source files as they are added to the underlying src folder (sigh).
    In practice you will see a lot of linkage errors that can be easily fixed by adding the missing files from src/LinearMath/, src/BulletSoftBody, src/BulletCollision etc…
  11. (optional) fix the warnings that appear here and there and spoil the build.

Why do it this way?

There are several assumptions underlying this approach:

  • You won’t update very often and would like to check in the source in your own repository, or maybe you don’t use version control but want to keep tidy. I use the so called ‘ext’ folder for third party stuff.
  • You want a separate library; for this to work with iOS it has to be a static library.
  • You don’t want to ‘rearrange’ the archive content. You just want to refer the files you need. Using the archive ‘as is’ makes it easier to setup on several computers (you can check in your project along with the archive so anybody on your team can build it).
  • You want to have ‘unit tests’ handy so you can write tests while you’re learning how to use the library. I like to write tests to make sure I understand how the library works, and later the same tests can help me update to a newer version of the same library. Plus I find it much easier to write a few tests that output to the command line, rather than doing a big upfront integration with my software.
  • If you look at the sources it should become clear that you don’t need everything. I use AllBulletDemosOSX because it already contains references to most of the source files we need, so it saves time and effort (thanks to the bullet forums for the tip)

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

  • To rename a project, you can use the project navigator or the file inspector. You can rename a project the same way you rename a file in your xcode workspace and xcode will try to help you rename various entries. It’s easier than renaming the *.xcodeproj file yourself.
  • You may need help to setup unit tests. If you’ve never done it please consider doing it as it’s well worth it and there are good articles about this lying around.