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…
- btBvhTriangleMeshShape. This gets populated using an instance of btStridingMeshInterface.
- btTriangleMesh, an easy to setup implementer of btStridingMeshInterface.
- btVector3, instantiated using 3 arguments of type btScalar
- btScalar – a typedef for float.
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.


Comments