Best Practices and Recommended Literature |
This section contains a collection of best practices and tips for stable simulations and a reference of recommended literature.
Rigid body dynamics is a complex topic and it takes time and a lot of experiments to fully understand the physics simulation. It is easy to make a fast but unstable simulation. It is easy to make a stable but slow simulation. Making it stable and fast at the same time requires experience. Here is a collection of tips to improve the stability of physics simulations.
This topic contains the following sections:
Tweak the sleeping settings in SleepingSettings. Sleeping can be very helpful to increase performance and stability because it can deactivate small jittering objects. On the other hand it can cause problems when objects start to sleep too early. Typical example: A stack of boxes should fall but freezes in an unnatural tilted angle.
Use a Damping force effect to damp the velocities of the rigid bodies.
Use lower gravity for stable stacking. Stacks of boxes are more stable if a low gravity acceleration is used. If stacking is important and a low gravity (objects will fall slower) can be tolerated by the game audience, try to use a smaller gravity value, for example:
Simulation.ForceEffects.Add(new Gravity() { Acceleration = new Vector3F(0, -5f, 0) }); // 5 m/s² instead of 9.81 m/s²
Use small mass ratios. The mass of the lightest dynamic object compared to the heaviest dynamic object should be around 1:10.
Use small restitution values. Large restitution values creates a lot of bouncing and it is favorable to have a simulation where objects come to rest very quickly.
Tweak the number of constraint iterations in ConstraintSettings. The constraint solver uses an iterative algorithm. Increase the number of constraints to create more stable simulations (especially visible in stacks of rigid bodies). Decrease the number to reduce the simulation time at the cost of stability.
Avoid conflicting constraints: If constraints enforce incompatible goals the simulation will get unstable. Motors should be disabled when they would violate another constraint. For example, a velocity motor should be deactivated when the allowed limit of another constraint is reached.
If a rigid body should not rotate (relative to world space), the properties LockRotationX, LockRotationY and LockRotationZ can be used instead of constraints.
Tweak the time step size in TimingSettings. Decreasing the time step size makes the simulation more stable, but one simulation update will take significantly longer. Increasing the time step size reduces the simulation time but can cause more instabilities.
For debugging, set the simulation time step size to a small value, for example:
Simulation.Settings.Timing.FixedTimeStep = 0.001f; // 1 ms. Simulation.Settings.Timing.MaxNumberOfSteps = 100; // A large value.
A small time step is bad for performance, but helps to check if any simulation problems and instabilities are related to the current time step size.
Remove objects from the simulation when they leave the area of interest: If a tree falls in a forest and no one is around to observe it, is its physical behavior realistic? - In most games, the answer is: Nobody cares. Therefore, try to remove objects that only cost simulation time and are not relevant for the gameplay anymore.
All objects should have an extent around 1 because the simulation settings are optimized for this case (which is the most useful case in games). Standard simulation settings cannot simulate very small objects (e.g. 0.01 units sphere diameter). Try to scale your whole scene so that your ball is for example 1 unit in diameter. Increase the gravity if the object fall speed appears to slow.
The CollisionDomain of the simulation contains a collision object for each rigid body. You can also add other collision objects to the collision domain (e.g. to create trigger volumes). Per default, the collision domain of the physics simulation computes collisions between all collision objects. The simulation only needs collision information involving dynamic rigid bodies. It is recommended to use collision filters to avoid the computation of unnecessary collision information. (See also The Simulation - Collision Detection)
Applications should set the CollisionGroup property of a collision object and use this to filter collisions. (Collision groups are simple integer IDs and the meaning is application specific.)
The collision domain computes collision information between non-moving bodies only once and caches this information. Nevertheless, on less powerful systems, like the Xbox 360, it can still improve performance to filter collisions between static bodies. This can be done in a broad phase filter based on collision groups, or with a simple filter like this:
_simulation.CollisionDomain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>( pair => { var bodyA = pair.First.GeometricObject as RigidBody; if (bodyA == null || bodyA.MotionType != MotionType.Static) return true; var bodyB = pair.Second.GeometricObject as RigidBody; if (bodyB == null || bodyB.MotionType != MotionType.Static) return true; return false; // Do not compute collisions between two static bodies. });
In general, games should avoid physics scenarios where many objects are in a pile or stacked. For example, a wall with 100 bodies is much harder and slower to simulate than 100 scattered bodies. See also Simulation Islands.
Do not initialize bodies in start positions that create conflicts, e.g. one body partially stuck in another body.
One method to find good start positions offline is: Set up the bodies. Simulate for a few time steps until the bodies come to rest. Save the resting position and use this position to initialize the bodies in the game.
If a simulation scenario does not work in your game, try to test it in the Samples. The physics samples provide the basic setup for a simulation. If a simulation scenario works in a physics sample but not in another game, then there is probably a problem with the simulation settings or the order of operations in the game.
The samples have other features that help to debug a simulation:
Automatic drawing of bodies: Rigid bodies are drawn automatically. If you don't see a body, the collision object is probably not where it should be or the scale is wrong and the player camera is inside the body. Also, triangle meshes are one sided; the rendered side is the "solid" side. Maybe the triangle winding order of a mesh must be reversed.
Drawing contact information: Press 'C' to enable rendering of contact information (positions and normals). Are there contacts between two penetrating bodies? Do the contact normals point into valid directions?
Single-stepping: Press 'P' to pause a simulation and then press 'T' to advance the simulation by a single time step.
A free introduction into game physics and rigid body dynamics can be found here: A Unified Framework for Rigid Body Dynamics.
Many helpful topics and links can be found in the DigitalRune Blog.