Disabling collisions between linked bodies

Aug 26, 2009 at 12:41 AM

Hi all,

In ODE physics there is the fairly common concern of disabling collisions between bodies connected by joints so that contacts do not disturb the joint's stability. In Farseer this can also be done using CollisionCategories. However, this is not sufficient for collisions between such composite objects. An example for clarity:

Composite: BodyA -- LinkedTo -- BodyB

Collision: Composite1's BodyB should collide with Composite2's BodyA.

So the thing is, only collisions between linked bodies should be disabled. The problem is, I can't seem to find a way to check whether two bodies are connected in Farseer. Is there an easy way to make a generic implementation of this functionality of disabling collisions between linked bodies?

Best regards,

Gonçalo

Aug 26, 2009 at 1:28 AM

You can use the CollisionGroup (along with CollisionCategories and CollidesWith). Any geometries in the same CollisionGroup will not collide. This is a convenient method if your objects start out linked. It wouldn't work so well if you wanted to dynamically link any two bodies in the system and wanted them not to collide once linked.

The other method I can think of that might work better in this situation is the bool OnCollision() callback. You could put some information about the linked objects into the geometry Tags and use it in your OnCollision to return false for collisions between linked bodies, causing the collision to be cancelled.

As for a generic implementation, one (very quick and probably silly) idea that involves editing the engine is this:

  1. Put a "CancelCollision" property on springs & joints
  2. In the discarding arbiter phase, go through all joints & springs and cancel those arbiters that are betwen linked geometries.

However, this probably wouldn't work so well - think of the scenario of a chain of linked bodies. BodyA---BodyB---BodyC. This generic solution wouldn't be able to cancel collisions between BodyA and BodyC. The more I think about it the more I don't think a generic solution should be implemented in the engine. It should be handled by the "Composite" object that handles all bodies, geoms, joints and springs.

Aug 26, 2009 at 1:49 AM
Edited Aug 26, 2009 at 1:54 AM

Thanks for the answer,

Sadly, it seems like my first impression was right and it will not be easy to achieve this in Farseer. As I mentioned in my original post, static CollisionCategories don't really work for what I want, and it's not a matter of dynamically created joints.

Suppose A links to B. This setup is a composite object (e.g. a Composite class which creates A, B, and the link). What I want is to be able to instantiate 2 Composite objects and have all bodies collide with all bodies except those which are linked under the same Composite. I'm sorry if I'm not making myself clear, but the situation is really very simple, and indeed natural for many complex articulated systems I've worked on before.

About your second proposal, it should indeed work, but unfortunately it places too much of a burden on geometries themselves (e.g. the OnCollision events of both geometries will have to be called and rejected). Also, it will lead to tightly coupled code.

Probably what I'll do is try to adapt the ODE solution to Farseer. Basically:

1. Keep a list of attached joints on the Body's Tag object. The list will have to be maintained when joints are attached or removed from the body.

2. Use this list to implement a helper IsConnectedTo() method that I can use to check whether a Body is connected to another via a joint.

3. Hook to the general BroadPhase OnCollision event and exclude pairs of geometries linked to bodies which are connected via joints.

In this way excluded collisions will be caught even before any narrow collision tests are made (i.e. more performant) and it can be applied generally to all geometries in a scene.

I think you're right that a generic solution shouldn't be on the engine. ODE engine also doesn't assume this, but there is an easy and engine-integrated way to find out which bodies are connected, which helps tremendously in implementing this and other collision schemes.

Best regards,

Gonçalo

Edit: I just noticed that things will be even more complicated since the abstract Joint class interface doesn't have information about the bodies linked to the Joint. So every solution will have to be tailor-made for each joint type, for each object scenario. Ouch...

Aug 26, 2009 at 2:31 AM

Ok, done it. It wasn't half as bad as I expected, as my game engine had already abstracted away all the joint creation stuff :-) Basically, I managed to get by with the following three extension methods:

        public static void AddLink(this Body body, Body other)
        {
            var linkList = (List<Body>)body.Tag;
            if (linkList == null)
            {
                linkList = new List<Body>();
                body.Tag = linkList;
            }

            linkList.Add(other);
        }

        public static void RemoveLink(this Body body, Body other)
        {
            var linkList = (List<Body>)body.Tag;
            if (linkList != null)
            {
                linkList.Remove(other);
            }
        }

        public static bool IsConnectedTo(this Body body, Body other)
        {
            var linkList = (List<Body>)body.Tag;
            if (linkList != null) return linkList.Contains(other);
            return false;
        }

And then the handler to exclude invalid collision pairs:

            simulator.BroadPhaseCollider.OnBroadPhaseCollision += (g1, g2) =>
            {
                if (g1.Body != null && g2.Body != null && g1.Body.IsConnectedTo(g2.Body)) return false;
                return true;
            };

Works like a charm. My only qualms is with having to rely on the Tag object of Body. Usually Tags should only be used for application specific data, not for hooking general functionality (because then you can't really have two libraries doing the same now can you? :-P)

Best regards,

Gonçalo

Aug 26, 2009 at 9:21 AM

Very interesting approach on handling the collisions. Thanks.