The StaticMesh provides an example of what would be needed. It inherits Collidable and implements ISpaceObject.
The harder part is building the collision pair handlers. The pair handlers govern the interaction between two collidables. You can see the full list in the BEPUphysics.NarrowPhaseSystems.Pairs namespace. The StaticMeshPairHandler and other existing pairs will help guide a custom pair's development.
Let's start with the StandardPairHandler first. It requires two fundamental things- a contact manifold and a constraint. The contact manifold manages and updates the contacts between two objects. The constraint manages the solver representation of those contacts to support rigid collisions.
Fortunately, there's a lot of collision tests built in, so you don't have to do the hard part. If everything is boxes, it would be a good idea to look at the BoxContactManifold and the BoxBoxCollider. The BoxBoxCollider is a static class which generates contacts from two box shapes. The BoxContactManifold uses those contacts to update its existing contacts. You'll notice that it has persistent contacts rather than replacing everything every frame; this helps with solver stability and some overhead.
You'll have a few options at this point. You could make your own version of the BoxContactManifold which works between the environment voxels and another box and blends contacts together using one of the built in contact reducers, or you can take the (probably easier, possibly better) route of initializing a BoxContactManifold for every active pair. This allows you to re-use as much code as possible.
If you do go down the route of initializing and maintaining a bunch of persistent BoxContactManifolds, the StandardPairHandler no longer fits very well. It's designed for pairs which have a single contact manifold, like convex-convex types and mesh-convex, where the mesh has many contact
testers, but only one manifold which combines and reduces the contacts. With multiple manifolds, you could either make a custom 'group manifold' and continue using the StandardPairHandler, or you could make it a 'group pair handler' designed to support multiple manifolds.
The existing GroupPairHandler and MeshGroupPairHandler show examples of how to approach this. They both collect and maintain child CollidablePairHandlers. You could go this route, but it was designed that way to provide a common base for multiple collision types. In your case, it may be best to make a custom version which maintains your bunch of ContactManifolds instead of whole CollidablePairHandlers. The overall design of the GroupPairHandler could still be used, though.
For your constraint, since you could easily end up with more than 4 contacts, you'll probably end up making a ConvexContactManifoldConstraint for each manifold and put them all into a single ContactManifoldConstraintGroup. This is similar to what the GroupPairHandler does.
It's a good idea to try to minimize the number of pair handlers you have to create. For example, if all your objects (environment and everything else) are boxes, you could make a single pair handler for box vs. environment. If there's non-box shapes, you might have to implement a second pair handler for convex vs. environment. As you might guess, it would be quite a pain to go through and have full support for every single shape type. Even though a single pair handler can theoretically cover multiple pair types (like the convex-environment mentioned above), there's just so many different acceleration structures in play for the more complex nonconvex shapes (like mobile meshes) that it would be tedious.
So, to summarize the approaches to making a pair handler for your environment:
1) Use a StandardPairHandler and make a custom group ContactManifold which holds multiple other child ContactManifolds. Use a ContactManifoldConstraintGroup which holds the child ConvexContactManifoldConstraints.
2) Make a fully custom "group" pair handler which manages multiple contact manifolds directly without the need for a contact manifold group. Would still probably use the ContactManifoldConstraintGroup.
3) Make a group pair handler very similar to the existing GroupPairHandler or MeshGroupPairHandler that manages multiple child pair handlers, each with their own way of handling the involved collidables. Your group pair handler would once again use a ContactManifoldConstraintGroup to bundle up every child's contact constraint.
4) Make a contact manifold which uses BoxBoxCollider queries to collect contacts and then uses a built-in contact reducer to bring it down to 4 total contacts. The contact constraint could then just be a NonConvexContactManifoldConstraint. For robustness, you'd want to update old contacts instead of replacing them whenever possible (via matching contact ids+source pairs or just nearby position and similar normals).
Finally, you'll also need to tell the engine to use your pair handler. The engine keeps track of a list of type pairs and their associated pair handler type. You can add/remove pair handlers by doing this:
Code: Select all
NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(Class1), typeof(Class2)), new NarrowPhasePairFactory<YourPairHandler>());
Since most of the existing classes rely on either Collidable or CollisionShape instances, pooling and re-using them will be important to avoid garbage collection. The number of collision pairs will be extremely small relative to the number of blocks in the terrain in any reasonable situation, so memory usage will still be pretty light.