Hello World - ECNUPendulumRot/box3d-wiki GitHub Wiki
In this section, we will briefly explain how to create a simple simulation scene. It should be noted that this section only covers the main steps of creating a scene, and the complete creation method requires some additional steps.
Creating a World
In Box3D, simulation begins with creating the world. We first need to create a b3World object as the stage for the simulation. b3World provides functions such as memory management, object creation, and simulation.
The process of creating a b3World object is very simple. You can create a b3World object by only setting gravity.
b3Vec3r gravity(0.0f, 0.0f, -10.0f);
b3World world(gravity);
Once we have created the world, we can add various bodies to it.
Creating a Ground Body
First, we will create a static object to serve as the ground for the world.
Bodies are built using the following steps:
- Define a body with position, damping, etc.
- Use the world object to create the body.
- Define fixtures with a shape, friction, density, etc.
- Create fixtures on the body.
According to step 1, we need to define a body definition of the ground body. In this definition, we define the initial position and rotation of the ground body and set its type to a static object, to ensure that the ground will not move when interacting with other objects.
b3BodyDef groundbody_def;
groundbody_def.set_init_pose(b3Vec3r(0.0f, 0.0f, 0.0f),b3Vec3r(0.0f, 0.0f, 0.0f));
groundbody_def.m_type = b3BodyType::b3_static_body;
For step 2, We need to create corresponding objects in this world through body definition.
b3Body* ground = world.create_body(groundbody_def);
For step 3, we create the shape of the ground. The most common and simplest ground shape is a plane, so we create a plane shape. To create a plane, we need to provide length and width in meters.
b3PlaneShape plane_shape;
plane_shape.set_as_plane(10, 10);
Finally, in step 4, we create the shape fixture and and attach it to the ground body. Just as body definition is required before creating a body, adding a fixture also requires fixture definition first. In the fixture definition, we can set the body's shape, friction, restitution coefficient and other properties. Here we only set the shape and density. Static objects do not move, so their mass is set to 0.
b3FixtureDef fixture_def;
fixture_def.m_shape = &plane_shape;
fixture_def.m_density = 0.0f;
ground->create_fixture(fixture_def);
Creating a Dynamic Body
The process of creating a dynamic object is very similar to creating the ground, and it is also carried out according to the above four steps. The main difference is that we need to set its body type to dynamic_body and set a normal mass for it because dynamic objects need to consider collision. Of course, dynamic objects are generally not set to plane shapes.
First, we create the body using CreateBody.
b3BodyDef body_def;
groundbody_def.set_init_pose(b3Vec3r(0.0f, 0.0f, 10.0f),b3Vec3r(0.0f, 0.0f, 0.0f));
body_def.m_type = b3BodyType::b3_dynamic_body;
b3Body* cube = world.create_body(body_def);
Next, we create a box shape and attach it to the dynamic body. When creating a box, we need to provide the half length of its length, width and height.
real box_hf_size = 1.0f;
b3CubeShape cube_shape;
cube_shape.set_as_box(box_hf_size, box_hf_size, box_hf_size);
Here we set the friction coefficient, restitution coefficient and density of the box. Using the fixture definition we can now create the fixture. This automatically updates the mass of the body. You can add as many fixtures as you like to a body. Each one contributes to the total mass.
b3FixtureDef box_fd;
box_fd.m_shape = &cube_shape;
box_fd.m_friction = 0.0;
box_fd.m_restitution = 1.0;
box_fd.m_density = 1.0;
cube->create_fixture(box_fd);
After creating the dynamic body, we can start the simulation.
Simulating the World
Once we have the ground and dynamic objects, we can start to make time flow and simulate. In Box3D, time is divided into discrete time steps of equal length, and the position and velocity of the object are updated in the form of numerical integrators. Generally speaking, we divide one second into 60 time steps, that is, 1 time step corresponds to 1/60s.
The simulation process in a time step is roughly like this. First, collision detection is performed to obtain all constraints in the current time step, and then the solution phase is entered. During the solution process, the solver will handle the constraint pairs that are violated and solve the constraints as much as possible. The solution is divided into velocity constraint solution and position constraint solution. Since Box3D uses an iterative solver, the number of iterations must be set separately. The solver will iterate the specified number of times to solve the constraints. After the solution is completed, the solver will update the velocity and position according to a certain integration method, so that the object can show the expected movement phenomenon.
You can set the time scale and number of iterations corresponding to a step in a world like this:
float timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
world.step(timeStep, velocityIterations, positionIterations);
In addition, some scene registration work is required to register the scene to the sample collection. In this way, when you run the program, you can see the simulation effect in the graphical interface. All the demos we provide in the Box3D Testbed are created according to this process.
Cleanup
When a world leaves scope or is deleted by calling delete on a pointer, all the memory reserved for bodies and fixtures is freed. This is done to improve performance and make your life easier. However, you will need to nullify any body and fixture pointers you have because they will become invalid.