5
\$\begingroup\$

I've been stuck for the past few days on implementing multiple body collision response, and I can't seem to find any good resource to help me advance.

Colliding between two objects is simple enough. What I have so far is this:

    public static void ResolveCollision(ref Vector3 aVelocity, float aMass,
                                        ref Vector3 bVelocity, float bMass)
    {
        var totalMass = aMass + bMass;
        var temp = (aMass / totalMass * aVelocity) + (bMass / totalMass * bVelocity);
        bVelocity = (bMass / totalMass * bVelocity) + (aMass / totalMass * aVelocity);
        aVelocity = temp;
    }

This works fine in resolving collisions individually between objects. The issue that I need to resolve is when two or more bodies are involved in the calculation. For example, pushing an object against a wall or pushing two objects next to each other in the same direction. The component missing in my code is summing up the masses of the objects involved so that the final displacement is believable.

I am hesitant to implement a solution that once resolving the collision between A and B, that B will go and test its movement and resolve collisions between B and C, and return a response back to A to adjust itself to account for any findings, because that could become messy and recursive.

I have also considered an "island" approach, where connecting bodies form an "island" that has a total mass which would be used when resolving collisions. However, this does not solve for the case of pushing an object against a wall, as I would omit walls and floors from being part of islands as their infinite mass would affect calculations of pushing objects vertially or horizontally respectively, if they are contributing their mass to the island.

Are either of my suggestions close to the mark, or what kind of pattern could I use to efficiently resolve collisions between multiple bodies?

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Most game physics engines just resolve collisions pairwise. The solution isn't perfect, but it keeps the code simple so you can run more physics steps and iteratively converge on a better solution from multiple passes. \$\endgroup\$ – DMGregory Aug 9 '20 at 11:42
  • \$\begingroup\$ That's a really helpful comment - and yes, the pairwise collision resolving I have at the moment is doing well. However in the case of A pushing object B pushing object C (A -> B -> C), A's final velocity is not calculated in relation to the total mass of B + C - only considers mass of B, and therefore moves faster than expected. Is the solution in this case something as simple as to resolve penetration the following frame to push A + B back apart? \$\endgroup\$ – garanon Aug 9 '20 at 12:22
  • 1
    \$\begingroup\$ I wouldn't be surprised, if we were to reconstruct an equivalent test in common physics middleware like PhysX, Box2D, or Havok, if they showed the same error in A's outgoing velocity. Chains of body interactions are a known weakness in these tools — see some additional examples in this vein in Bennett Foddy's GDC talk \$\endgroup\$ – DMGregory Aug 9 '20 at 12:30
  • 1
    \$\begingroup\$ I appreciate it mate. Your explanation and also Bennett Foddy's explanation has answered it pretty much. If you want to write it as an answer I'll mark it as correct, otherwise I'll just write it myself. \$\endgroup\$ – garanon Aug 10 '20 at 12:21
  • 1
    \$\begingroup\$ Please do! It's been a while since I dug into this in depth, so I expect you can write a better answer with the problem space fresh in your mind. \$\endgroup\$ – DMGregory Aug 10 '20 at 12:22
2
\$\begingroup\$

I'm writing the answer for anyone interested, or who stumbles down the same path as me. Credit goes to DMGregory and Bennett Foddy.

The common solution present in many physics middlewares, is to just iterate the same list of collision pairs multiple times and only individually resolve collisions. The expected result is something that can be deemed as "good enough" in a performance critical environment.

Specifically to my question above, given objects sitting in a row: A -> B -> C, and applying a force to A

  • A will resolve with B (and yes, only accounts for the mass of the two)
  • B will resolve with C. B gets given a new velocity
  • In a second iteration, A will resolve with B again which has a new velocity, pushing backwards on A

A pseudo-code example might look as follows:

while numIterations < desiredIterationCount
{
    foreach collisionPair in collisionList
    {
        resolve collision
        update position of each item in pair
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.