BEPUphysics uses an
overall design scheme as follows:
Entities,
such as convex polyhedra, are contained in a
Space.
Entities
compose all dynamic and nondynamic objects within the world.
Interaction
Handlers such as Controllers and Constraints manage behavior
between Entities.
Helper Classes,
specifically the Toolbox and PrimitiveToolbox, provide
shortcuts and easy methods to accomplish complex tasks and computations.
General Tips:
-Avoid using very large or very small objects. These can
cause sometimes noticeable artifacts.
-Avoid large mass ratios. Very heavy objects sitting on top
of light objects can be unstable.
-While entity margins are adjustable, avoid extremely small values.
-If something isn't clear, be sure to ask on the forums or let
Norbo know!
Have questions that aren't addressed
here? Head to the
forums or contact
Norbo directly. Forums are the
preferred method of communication as others may learn from what is
posted there. The library comes with full XML documentation for
in-code viewing.
Entities
All simulated objects
fall under the category of Entity. Entities are
stored within and updated by their associated
Space object.
There are currently
nine base types of Entity:
Box
Specialized primitive with a mathematical definition,
well suited for crate duty.
Capsule
Spherically expanded line segment; a pill.
Cylinder
Mathematically defined object with a height and radius with two
circular ends.
Cone
Mathematically defined object with a height and radius with one
circular and one single-point end.
Sphere
Simple mathematically defined object with a radius.
Triangle
Three vertices connected by three edges.
MinkowskiSum
Sweeps the two component entities through each other to form a new
shape.
ConvexHull
A triangulated exterior shell of a point set.
WrappedBody
An implicit convex hull around a set of shapes.
-Note that while
the display
graphics of the Cylinder, Capsule, Cone, and Sphere are
triangulated, they are considered to have 'perfect' curves during
simulation as they are defined through equations instead of a series of
triangles.
Each basic type of
Entity
can be either physically simulated or not. Switching
between these states is as simple as calling Entity.makePhysical(float
mass) or Entity.makeNonDynamic(). Physical
objects respond to collisions and operate based on forces.
Nondynamic objects, on the other hand, operate purely on the velocity
level. In collisions, they are considered to have infinite
inertia.
A special type is CompoundBody;
other entities can be added to its listing by
using the function addBody(Entity body), or removed
by using the removeBody(Entity body) method.
When added to a CompoundBody, an Entity's relative
position to the CompoundBody and its existing elements becomes
fixed and the object will act as a part of the CompoundBody
physically. CompoundBodies can be
added to other CompoundBodies, allowing for hierarchies of
objects.
World
and Environment:
Space
Obviously, there needs
to be somewhere to put all of the objects to be simulated. This is
handled through the Space class.
A Space object
can be created with no parameters or with a list of
entities.
To add additional objects after creating the Space, call
add(Entity entity). This will place the entity in the
list of entities to be updated each frame. Conversely, objects can
be removed from the update loop by calling remove(Entity entity).
Constraints can be added and removed by using the
add(Constraint constraint) and
remove(Constraint constraint) functions, respectively.
To move the simulation
forward, simply call the update(GameTime gameTime) method of the
Space object. Also available are the update(float dt,
GameTime gameTime) method and other auxiliary methods. If the
simulation should slow down into 'moon gravity' during intense
interaction, the Game's isFixedTimeStep should be set to false
and the second method (update(float dt, GameTime gameTime))
should be used, with dt being a value less than or equal to
1/60f.
Simulations can be set
to run with adaptive quality based on the current performance using the
activateDynamicIterationCount(float desiredFPS, int minIterations,
int maxIterations) function. If the time since the last drawn
frame is less than 1/desiredFPS, the iteration count will
increase by 1 up to a maximum of maxIterations. Conversely,
if the time since the last drawn frame is greater than 1/desiredFPS,
the number of iterations will decrease by one per frame until the
minimum is reached. If the current FPS is extremely low, the
decrease rate is faster.
If desired, a list of
all contact
points between objects in the simulation during the current frame can be
obtained by calling getContacts(); however, as this compiles the
list from individual
Controllers at the time of the
request, it is not recommended for frequent calls.
A raycast against the entire world can be performed by using
Space.rayCast; this searches through the broad phase listing
and any ray castable containers (such as static triangle groups) within
the world.
Additionally, there are a
set of important fields contained in a Space's
SimulationSettings which can be used to
tune the simulation. These range from varying position correction
and integration methods to the lower bound on velocity before being
clamped to zero. Other collision detection options are also
available here, allowing continuous collision detection to be enabled
and disabled.
Broad Phases
Broad phases provide a method for determining
collision pairs. They can also be queried with bounding shapes for
determining objects in an area. Beyond the following, custom broad
phases can be derived from the BroadPhase class and
used in the space.
UniformGrid
Separates the space into
an infinite number of cubes. Objects within these cells are
checked only against other entities within the applicable cells.
This type of grid is rebuilt every frame, lowering the bookkeeping costs
but providing suboptimal performance for simulations with many nonmoving
objects. Recommended for simulations in which most or all entities
are moving.
PersistentUniformGrid
Similar to the above, but keeps track of objects through
frames and does not rebuild the representation every frame. A
generally good fit for most simulations; used by default.
BruteForce
Simple pairwise check
between entities with no spatial partitioning. Provides acceptable
performance only for small (low hundreds or less) numbers of objects.
Broad phases also support methods for getting entities within bounding
volumes and raycasting against their contents.
Updateables and Other Frameworks
The engine supports a framework for new types of objects to be
maintained by the space. These include Updateables,
SolverUpdateables, CombinedUpdateables, and ForceFields.
Default subclasses of these are listed below; others can be added
externally.
Static Triangle Groups : Updateable
An efficient container for complex static triangulated
geometry. Can be loaded in based on a mesh. Capable of
handling thousands of triangles quickly.
Static Groups : Updateable
Nonmoving elements of the simulation, such as level geometry,
can be represented within StaticGroups. The
entities added to a StaticGroup will be added into the
associated space dynamically as needed (such as when physically
simulated bodies approach). With large amounts of geometry, the
computational savings can be great. Note that entities added to a
StaticGroup need not be added directly to the space;
the StaticGroup will handle all of the adding and
removing.
Terrain : Updateable
A conceptual subset of static groups, Terrain
converts a list of heights into appropriately placed triangles
dynamically. As with static groups, the triangles will persist
only when necessary. Heights can be modified on the fly, allowing
deformability.
Vehicle : CombinedUpdateable
Vehicles are wheeled mechanisms that can be driven around
while saying "vroom vrooooom rrrrrrrroooom." They support numerous
friction coefficients, braking, acceleration, and tuning variables.
In order to get a solid feel for the friction forces of the tires,
vehicle force calculation needed to be integrated directly into the
solver. Additionally, to update the graphical portion of the
vehicle (wheel positions relative to interpolated positions), the end of
frame update component of CombinedUpdateable is used. Using the same basis
or directly using the SolverUpdateable, other types can be directly tied
into the solver. This has the benefit of letting forces and
impulses applied during the updates to be 'felt' across the simulation,
causing the propagation of momentum rather than stopping nonphysically.
PushField : ForceField
The pushfield is the simplest available forcefield; it is
simply a uniform application of the same force with a maximum speed.
Tornado : ForceField
Showing off a little of what can be done with the framework,
a tornado incorporates three position-dependent forces to form a
whirling mass of air.
GravitationalField : ForceField
Applies position dependent forces based on a center origin
and a constant value. The constant value can be thought of as the
product of the gravitational constant and the mass of the object.
In the default demos example, considering the real world gravitational
constant, the 'planet' has an effective mass of 10,000,000,000,000
kilograms.
_______
Helper
Classes
There are two main
helper classes; the Toolbox and PrimitiveToolbox.
Toolbox:
Contains numerous math and geometry tests. Includes methods
for:
-Segment/Ray - Triangle Tests
-Point - Triangle Tests
-Line - Line Tests
-Triangle - Triangle Tests
-Point - Plane Tests
-General Entity/Entity Tests
-Ray-Entity tests
-Miscellaneous vector, float, list, and quaternion operations
Additionally, the Toolbox contains computational constants
epsilon and bigEpsilon, corresponding to floating point
tolerances. Default values are epsilon = 1E-7f and
bigEpsilon = 1E-5f.
PrimitiveToolbox:
Contains methods for easily creating common shapes.
Includes methods for:
-Tetrahedra of arbitrary vertex
positions and right tetrahedra
-Hexahedra of arbitrary positions
or rectangular prisms and cubes.
_______
Interaction
Handlers
Force
Forces can be created and applied to physically simulated
objects. Based on the origin and direction of force, the target is
pushed. The magnitude of the push is determined by the length of
the direction vector.
Additionally, Forces can be set to track the
target in either or both linear and angular motion. This can be
used to simulate 'thruster' behaviors. By default, tracking is
disabled. If tracking is enabled, the default behavior is for both
linear and angular motion to be tracked. These settings can be
adjusted through the Force's isTrackingTarget and
isChangingDirectionWhileTracking fields.
To apply a Force, use an entity's applyForce(Force force) method. To remove it
from the object entirely, use the removeForce(Force force)
method. A Force can be temporarily turned off without
removing it from an object by setting its isActive field to
false.
Constraint
Constraints can be formed between two Entities.
They restrict motion and provide an extra degree of interaction.
As of v0.6.0, there are four two-body velocity solver constraints:
BallSocketJoints, PointOnLineJoint,
DistanceConstraint, and DistangeRangeConstraint.
All of these and those below can be found in the "More Constraints"
demo.
Examples of Combination Constraints:
Fixed Point: A 'weld' joint can be created by
using three BallSocketJoints. The most stable configuration
is having each BallSocketJoint's anchor offset along a different
orthogonal axis from a midpoint between two objects (in other words,
each BallSocketJoint has a slightly different anchor point).
Revolute: 'Hinges' can be made by two
BallSocketJoints. The axis of rotation allowed by the hinge is
the vector from the first BallSocketJoint anchor point to the
second BallSocketJoint anchor point.
Prismatic: 'Sliders' can be formed by three
PointOnLineJoints, with each anchor location offset in a similar
fashion to the fixed point and each PointOnLineJoint's axis
parallel to the others.
Each Constraint
has two primary tuning variables; softness and bias factor. Higher
softness values allow the constraint to 'give' somewhat.
Generally, softness values are low, ranging from 0 to 1. The bias
factor is a modifier of the speed at which the constraint corrects
position drift, and is within a similar order of magnitude, though a
value of .2f works well in almost all situations. Values close to
0 will cause noticeable position drift, while values closer to 1 can
cause the constraint to explode.
If instability is observed in a simulation involving constraints, tuning
these variables can often alleviate the problem. In many
problematic cases, increasing the softness can help stop overzealous
adherence to the constraint.
Constraints can
also have a maximum force limit specified. When violated, the
constraint will be removed from simulation. In the future, motors,
friction, and motion limits will be added.
SingleBodyConstraints are solver-based types which affect only a
single entity. Examples include the MaximumSpeedConstraint
and RotationalAxisConstraint. Other single body affecting
types which aren't a part of the solver include GrabConstraint
and UprightConstraint. A special two-body
constraint that is not part of the solver, the Spring,
is also available.
Controller
Controllers manage the collision of two objects. They
persist over multiple frames, as long as the possible collision exists
(as determined by the broad phase collision detection). During
their lifespan, Controllers will keep track of the state of the
collision. If the objects intersect, the Controller will
move them apart to a safe collision margin and create
Contact points to maintain noninterpenetration.
Contact
Contacts are generated by Controllers to keep objects
out of intersection. At each Contact location, an impulse
is iteratively calculated using the number of iterations defined
in the Space
class.
Collision Filters
Entities' collisionFilter field acts as a bitmask which checks
if a given collision is valid. If one or more of the 'enabled'
bits in the filter match the collided entity's field, the controller is
created. The setCollisionFilter method of
Entity provides an easy way of setting up the individual bits
without having to convert binary to decimal.
Adding entities to an entity's nonCollidableEntities
list will also prevent interaction. Setting an entity's
isTangible flag to false will result in them not interacting
with other objects, but it still generates Controllers.
This makes it a valuable as a 'detector,' which finds nearby candidate
entities.
Events
As of v0.6.0, individual events can be hooked for collision events by
using the Entity.addEventHook method.
Most events are deferred to the end of the frame, allowing for most
operations to be called
safely. However, there are three special 'immediate' methods:
contact created immediate, controller created immediate, and entity
updated immediate. The first two
events allow the modification of the contact and controller's data at
the exact time of creation, before they are used in any calculations.
The third acts as a callback for any additional logic that should be
performed with that entity.
The demos (#30) have an example of how to use the event system in game
logic.
Thread
Safety
As of v0.7.0, running BEPUphysics in a separate thread has become
significantly easier. Entity states such as position and velocity
are buffered so that reads get the last valid result and writes wait
until the engine is ready before changing values. Along with the
buffered states, unbuffered properties are available; any property with
a prefix of "internal," such as Entity.internalLinearVelocity, read and
write values directly. This can be handy for immediate changes
when it is known that thread safety isn't an issue.
Most of the space's operations, such as raycasting or adding entities,
are internally locked to ensure thread safety. Space also contains
synchronization objects for use by external operations. The engine
takes out locks on these synchronization objects as necessary, so
locking the lockerUpdate object will ensure that your code will not run
while the engine updates. The finer grained locks on entities,
controllers, constraints, and updateables provide additional control.
|