Dynamics Module - ECNUPendulumRot/box3d-wiki GitHub Wiki
The Dynamics module is the module we need to deal with frequently because all the dynamics parts of the engine are included in it. It contains bodies, fixtures and world.
Bodies
Bodies are the main actors in our simulation "show", representing movement through speed and position. Bodies can also be acted upon by forces, torques, and impulses. We will introduce some important concepts around the creation and use of body.
Body Definition
Before creating an body, you need to create a body definition. The creation of the body will initialize the body's properties according to the settings in the definition. Body definition is reusable, which means that multiple bodies can be created based on the same definition. This helps us batch generate a large number of bodies in a loop.
We will introduce some of the more important parts of the body definition.
BodyType
Depending on whether they are affected by forces, we divide bodies into two types: static and dynamic. Here is the way of how to set the body type:
b3BodyDef body_def;
body_def.m_type = b3BodyType::b3_dynamic_body;
And here are the definitions of these two types:
b3_static_body
Static bodies always maintain their original motion state in the simulation and are considered to have infinite mass, so we generally set bodies such as the ground or walls as static types. If users have special scene requirements, they can also set a non-zero speed for static bodies, which will cause the static bodies to move, but the movement of static bodies will not be affected by other bodies. Static bodies will not collide with each other.
b3_dynamic_body
Dynamic bodies are the most common type of bodies in the scene and can collide with all types of bodies. Dynamic bodies have finite mass and will change their motion state due to forces and collisions. Users can also set their initial velocities.
Position and Angle
When we define a body, we can set its initial position and angle. Position refers to the position of the body in the world coordinate system. You can imagine that the body itself maintains a local coordinate system, and the position of its origin is set by this method. The angle is similar, indicating the angle transformation of the body's local coordinate system relative to the world coordinate system. In Box3D, the angle of a body is represented by a quaternion. However, when setting the initial angle, for the convenience of users, it is allowed to pass in Euler angles for setting. The set_init_pose method will convert it into a quaternion for storage internally.
b3BodyDef body_def;
b3Vec3r p(0, 0, 3);
b3Vec3r q(0, 0, 0);
body_def.set_init_pose(p, q);
When we attach a fixture to a body, The relative position of the fixture will be affected by the set initial pose, so the body can also be regarded as a frame of reference.
Create Bodies
After we have created the body definition, we can start creating the body. The creation of the object needs to call the create_body method in b3World, so we need to create a world instance first. The introduction of b3World will be mentioned later. For now, we only need to know that body creation depends on b3World. After each world instance is created, it will be assigned a unique memory allocator. The creation and destruction of body instances are actually performed by calling methods in the memory allocator. The advantage of this is that there will be no memory fragmentation and the allocation efficiency is high.
b3World* m_world;
b3Body* cube = m_world->create_body(body_def);
Using a Body
After a body is created, the use of the body has just begun. We can view and set many properties in the body. We will list some of the more commonly used properties, including mass, position and velocity, force and torque etc.
Mass Data
There are four properties related to mass, namely mass (scalar), inverse of mass (scalar), center of mass position (3D vector) and rotational inertia (3D matrix). The mass of a dynamic body is not zero, so the inverse of the mass exists, while the inverse of the mass of a static body is 0 because it is considered to have infinite mass. The center of mass position is a local coordinate with respect to the body's own coordinate system and is used for collision calculations, while the rotational inertia is used in rotation-related calculations.
After changing the mass, if you need to reset it to the initial, you can call the reset_mass_data() method.
Position and Velocity
The position and velocity of a body can be viewed and set through the following interfaces:
b3Quatr b3Body::get_quaternion() const;
b3Vec3r b3Body::get_position() const;
void b3Body::set_quaternion(const b3Quatr& q);
void b3Body::set_position(const b3Vec3r& p);
Forces and Torques
The forces and torques of a body can be viewed and set through the following interfaces:
b3Vec3r b3Body::get_force() const;
b3Vec3r b3Body::get_gravity() const;
b3Vec3r b3Body::get_torque() const;
void b3Body::apply_force(b3Vec3r& force);
void b3Body::apply_gravity(b3Vec3r& gravity);
void b3Body::apply_torque(b3Vec3r& torque);
Fixtures
The function of b3Fixture is to attach a shape to a Body. A Body does not know its own shape. It contains one or more Fixtures, and each Fixture corresponds to a Shape. So multiple Shapes can be assembled into a Body.
Fixtures mainly include
- a single shape
- Broad-phase proxies
- density, friction and restitution
- pointer to the parent body
Fixture Creation
To simplify the process of creating a Fixture, the structure FixtureDef is provided, and the user sets the FixtureDef and uses it to initialize the Fixture.
b3Body* body;
b3SphereShape SphereShape;
b3FixtureDef fixtureDef;
fixturDef.m_shape = &SphereShape;
fixtureDef.m_density = 0.0;
fixtureDef.m_restitution = 1.0;
fixtureDef.m_friction = 0.0;
b3Fixture* fixture = body->create_fixture(fixtureDef);
This will create the Fixture pointer in the body, so there is no need to show the creation. And internally it will copy the shape on the heap, no need to worry about creating the Shape in a local scope and attaching it to the body via Fixture.
Density
The density in the Fixture is used to calculate the mass and inertia matrix of the body, it should be greater than or equal to 0. The reset_mass_data() function in the body is automatically called when it is created.If you want to get the shape mass held by a certain Fixture, you can get it by calling get_mass_data.
b3Fixture* fixture;
b3MassProperty massData;
fixture->get_mass_data(massData);
The relevant information is stored in massData.
Friction
Friction is used to simulate the sliding between objects. It is divided into static friction and dynamic friction. Box3d uses Coulomb's law, that is, the magnitude of friction is proportional to the friction coefficient and the support force (normal force). The friction coefficient is generally between 0 and 1. Of course, it can be designed to other values ββto express certain special scenes. When there is contact between objects, it is used to model the tangential force (impulse) between objects.
b3Body* body;
b3FixtureDef def;
def.m_friction = 0.5;
b3Fixture* fixture = body->create_fixture(def);
Restitution
The coefficient of restitution is used to model the elasticity of an object, and can range from 0 to 1. When it is equal to 0, the collision between objects is a completely inelastic collision, for example, a small ball falling from the air to the ground will be stationary on the ground.When it is equal to 1, the collision between the objects is completely elastic collision, when the ball hit the ground will rebound, and will return to the height of the initial velocity of 0.When the velocity between objects is very small and the recovery coefficient is not 0, the object will shake, in order to deal with this situation, Box3d's solution is to set a threshold, when the relative normal velocity of the object is lower than the threshold, the recovery coefficient will be treated as 0 to deal with.
b3Body* body;
b3FixtureDef def;
def.m_restitution = 0.5;
b3Fixture* fixture = body->create_fixture(def);
World
b3World manages the creation and destruction of bodies, and provides access to all objects in the world. It also manages all aspects of the simulation.
Creating and Destroying a World
Creating and destroying a world is very simple. You only need to provide a single parameter, gravity, to create a world. You can create and destroy a world using new and delete.
b3World* m_world = new b3World(gravity);
delete m_world;
Using a World
We can create and destroy bodies in the world, the specific methods have been mentioned in the body chapter. In addition, b3World can quickly destroy all bodies in the world by calling the void b3World::clear() method.
Exploring the World
When we refer to bodies or contacts, we are referring to bodies in a certain world. In a world, each created body will be stored in a corresponding list, and we can access them one by one through the world.
for (* body = myWorld->get_body_list(); body; body = body->next())
{
body->is_awake() == true;
}
Simulation
Simulation is the most important function provided by b3World. You can set information such as the time step and number of iterations of the simulation in b3World.
float timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
world.step(timeStep, velocityIterations, positionIterations);