bullet physics starter
In the following text we present Bullet physics starter with an object falling towards ground under the gravity force sample.
content
setup
First we need to install Bullet library, under Ubuntu 20.04 LTS it can be found in the repository as libbullet-dev
package. We will also need g++
, scons
and pkg-config
packages for easy building workflow.
use
sudo apt install libbullet-dev g++ scons pkg-config
command to install all required dependencies
Then clone bullet-physics-starter repository with
git clone https://github.com/sansajn/bullet-physics-starter.git
command.
build & run
Building is super easy, just run
scons
command from sample directory which creates hello
executable, then run ./hello
to run the simulation.
There are two objects in the simulation falling body and ground. Simulation itself is divided into multiple short burst of times called steps. In every step simulation will print position for both objects (ground is not moving so its position is 0,-56,0
during whole simulation).
You should see, something like this
$ ./hello
world pos object 1 = 2, 10, 0
world pos object 0 = 0, -56, 0
world pos object 1 = 2, 9.99722, 0
world pos object 0 = 0, -56, 0
...
tip: see scons-starter to get familiar with SCons building tool
sample description
Heart of the physics simulation in Bullet is world, world is a place where objects (bodies) can interact with each other and world itself through forces. Bullet workflow is simple, create world, fill it with some bodies, setup forces and run simulation for some amount of time.
Our sample hello works the same way, it creates world represented by btDiscreteDynamicsWorld
object type this way
btDiscreteDynamicsWorld world{&dispatcher, &pair_cache, &solver, &config};
do not bother with
dispatcher
,pair_cache
,solver
andconfig
variables for now
Then sample creates two bodies represented with btRigidBody
object types. One body for falling object and one for ground. In Bullet each body must have shape so bodies can interact with each other. In the sample ground is represented as a square btBoxShape
of side equals to 100 units and on (0, -56, 0)
position this way
btBoxShape ground_shape{btVector3{50, 50, 50}};
btDefaultMotionState ground_motion{translate(btVector3{0, -56, 0})};
btRigidBody ground_body{0, &ground_motion, &ground_shape};
Ground body ground_body
is then added into the world with addRigidBody()
member function this way
world.addRigidBody(&ground_body);
Then sample creates falling object body on (2, 10, 0)
position with a unit sphere shape btSphereShape
this way
btSphereShape sphere_shape{1};
btDefaultMotionState sphere_motion{translate(btVector3{2, 10, 0})};
btScalar mass = 1;
btVector3 local_inertia = {0, 0, 0};
sphere_shape.calculateLocalInertia(mass, local_inertia);
btRigidBody sphere_body{mass, &sphere_motion, &sphere_shape, local_inertia};
this time sphere_body
has also mass so its position will change during simulation based on applied forces (gravity in our case). One note there, body’s motion state is stored in btDefaultMotionState
object type (see sphere_motion
variable) rather than in btRigidBody
objects.
initial body position is
(2, 10, 0)
with a radius equal to 1 and so it will hit the ground on(2, -6, 0)
position with a center on(2, -5, 0)
Finally, at the end of the sample 150 step simulation is running, where each step represent 1/60s this way
for (int i = 0; i < 150; ++i) {
world.stepSimulation(1.f / 60, 10);
for (int j = world.getNumCollisionObjects() - 1; j >= 0; --j) {
btTransform trans = get_object_transform(world.getCollisionObjectArray()[j]);
cout << "world pos object " << j << " = "
<< trans.getOrigin().getX() << ", "
<< trans.getOrigin().getY() << ", "
<< trans.getOrigin().getZ() << "\n";
}
}
From the sample output we can see that the falling body ends on (2.00006, -5.00001, 9.15244e-05)
position as expected. Pretty cool, what do you think?
advanced tip: watch out other bullet samples from
bullet3/examples
directory