Graphics Reference
In-Depth Information
The 3D scene we have used in this recipe includes two static objects (the ramp and the
floor) and eleven dynamic objects (a ball at the top of the ramp and 10 stacked boxes at the
bottom). We have used a simple naming convention for the models in the scene, where the
occurrence of the
box
or
cube
text in the name indicates that we will use the mesh's extent
to define a box collision shape. For the names containing the text
sphere
, we create a sphere
collision shape; and for everything else we will use the vertices to define a triangular mesh
collision shape.
Any mesh in the scene with a name that contains
static
will be initialized as a static rigid
body (unaffected by gravity and immovable), by giving a mass of zero to the rigid body. All the
other shapes are created as dynamic rigid bodies.
During the render loop, we tell the physics world to
step
through the simulation. The amount of
time taken by the last frame in seconds is used to determine how many substeps the simulation
will attempt to catch up on. We have provided a value of seven as the maximum number of
substeps, which is based on the following rule to prevent the simulation from losing time:
Rule for determining values for substeps and fixed time step for a given time step (frame time)
This means our simulation will continue to keep up until the frame rate slows to approximately
9 FPS (that is,
1/9 < 7 * 1/60
).
By default, the physics simulation uses a fixed time step of one-sixtieth of a second, that is,
the simulation moves forward at one sixtieth of a second per step. If a higher frame rate is
used by the render loop, for example, 120 FPS, then the simulation will be interpolating one
in every two ticks. As we have just seen, running at a slower frame rate results in additional
substeps being applied in an attempt to keep up.
Apart from the physics simulation itself and setting the time, the key to this implementation is
the correct updating of each mesh's world affine transform matrix. The Bullet Physics library
uses a
MotionState
object attached to each rigid body in order to update the transformation
matrix of the underlying object. We have implemented our own
MeshMotionState
class that
supports retrieving and updating of the
MeshRenderer.World
property.
The collision shapes in the scene have been created in a local model space (with origin at 0,
0, 0), although the corresponding mesh's are not necessarily centered at the origin (they are
in scene space, not in model space). Therefore, our
MeshMotionState
class must translate
the world matrix to and from scene space as appropriate. This is done by taking the mesh's
extent (which is in scene space) and moving it back from its center point to the origin.
The world matrix calculation for setting the
MeshMotionState.WorldTransform
property becomes:
Matrix.Translation(-m.Mesh.Extent.Center) * value
.
The Bullet Physics library not only supports rigid bodies, but also supports soft bodies,
clothes, ropes, and constraints.