Search code examples
physicsrigid-bodieselasticity

How to find the velocity of 2 colliding rigid bodies?


So I'm jumping into a physics engine. The colliders for now are spheres and planes. I've found the depth of the collision and the normal at point of contact easy enough, but for the life of me I can not wrap my head around the distribution of energy.

The Bodies contain a Collider, a Mass, a Force vector (velocity * mass), an Elasticity value (0 no bounce, 1 complete bounce) and a Friction value (0 slippery sausage, 1 momentum vampire) I've googled to hell and back and everything comes up with 1D and 2D simplifications, but I've been simply unable to adapt these to 3D.

Edit: I tried following this page: http://www.plasmaphysics.org.uk/collision3d.htm. It seemed so simple but for some reason I still have no bounce with an elasticity of 1.

My implementation is below:

var v = new vec3(
    (body.force.x + other.force.x) / totalMass,
    (body.force.y + other.force.y) / totalMass,
    (body.force.z + other.force.z) / totalMass
    );
body.force.set(
    ((velA.x - v.x) * elasticity + v.x) * body.mass,
    ((velA.y - v.y) * elasticity + v.y) * body.mass,
    ((velA.z - v.z) * elasticity + v.z) * body.mass
    );
other.force.set(
    ((velB.x - v.x) * elasticity + v.x) * other.mass,
    ((velB.y - v.y) * elasticity + v.y) * other.mass,
    ((velB.z - v.z) * elasticity + v.z) * other.mass
    );

For elasticity I have tried both multiplying the elasticity of both bodies and getting the average of them; no change.


Solution

  • So a nights sleep, a bit of thinking and great help taken from the N+ physics explanation page I've hashed something together which works, though not necessarily physically accurate, for the sake of debugging it is split between many variables, but I have commented to the best of my ability.

        //we have detected a collision between A) body B) other
            //note: for the sake of making things easier to think about,
            //      anything moving into or along the collision normal is
            //      referred to as vertical, anything perpendicular to
            //      the collision normal, is referred to as horizontal.
        //minimum translation required to resolve the collision
    var mta = collision.normal.clone().multiplyScalar(collision.length);
        //the total mass involved in the collision
    var totalMass = body.mass + other.mass;
        //the ratio of the mass belonging to body
    var ratioA = body.mass / totalMass;
        //the ratio of the mass belonging to other
    var ratioB = other.mass / totalMass;
        //the average elasticity of the collision
    var elasticity = (body.elasticity + other.elasticity) / 2.0;
        //the friction of the collision
            //note: average works, but low values have strong effects,
            //      it is easier to work with if they are multiplied
    var friction = body.friction * other.friction;
        //the vertical force of body
    var vertA = -body.force.clone().normalize().dot(collision.normal);
        //the horizontal force of body
    var horrA = 1.0 - Math.abs(vertA);
        //the vertical force of other
    var vertB = -other.force.clone().normalize().dot(collision.normal);
        //the horizontal force of other
    var horrB = 1.0 - Math.abs(vertB);
        //the amount of force applied on body
    var forceA = body.force.length();
        //the amount of force applied on other
    var forceB = other.force.length();
        //the amount of vertical force applied on body
    var vForceA = forceA * vertA;
        //the amount of vertical force applied on other
    var vForceB = forceB * vertB;
        //the amount of horizontal force applied on body
    var hForceA = forceA * horrA;
        //the amount of horizontal force applied on other
    var hForceB = forceB * horrB;
        //the total vertical force of the collision
    var verticalForce = (vForceA + vForceB) * elasticity;
        //remove all vertical force from body
        //resulting in a horizontal force vector
    body.force.add(collision.normal.clone().multiplyScalar(forceA * vertA));
        //apply friction to the horizontal force vector of body
    body.force.add(body.force.clone().normalize().multiplyScalar(-friction * hForceA * body.imass));
        //apply the new vertical force to body
    body.force.add(collision.normal.clone().multiplyScalar(verticalForce * ratioA));
        //remove all vertical force from other
        //resulting in a horizontal force vector
    other.force.add(collision.normal.clone().multiplyScalar(-forceB * vertB));
        //apply friction to the horizontal force vector of other
    other.force.add(other.force.clone().normalize().multiplyScalar(-friction * hForceB * other.imass));
        //apply the new vertical force to other
    other.force.add(collision.normal.clone().multiplyScalar(-verticalForce * ratioB));
        //resolve collision taking into consideration mass
    body.transform.position.sub(mta.clone().multiplyScalar(ratioA));
    other.transform.position.add(mta.clone().multiplyScalar(ratioB));