1
\$\begingroup\$

I am trying to create a small game engine in Java using only basic openGL functions and implementing everything else from scratch.

I am trying to get a basic physics engine working (similar to box2D only much simpler), I managed to detect collisions between my different bodies using SAT and I followed this tutorial to try and implement collision resolution.

It seems to be somewhat working but there are still some issues left. The biggest one is that when I have multiple objects colliding they seem to be sinking into each other (however everything works fine with only two objects). Here's an example demonstrating what I'm talking about:Pile of objects sinking into eachother

Here is my code used to resolve collisions:

    /**
 * Resolves the collision
 */
public void         resolve()
{
    TekRigidBody    bodyA;
    TekRigidBody    bodyB;
    TekVector2f     rv;
    TekVector2f     impulse;
    TekVector2f     correction;
    float           normalVelocity;
    float           massSum;
    float           ratio;
    float           e;
    float           j;

    bodyA = collider1.gameObject.getBehavior(TekRigidBody.class);
    bodyB = collider2.gameObject.getBehavior(TekRigidBody.class);
    if (bodyA == null || bodyB == null || (bodyA.getInvMass() == 0f && bodyB.getInvMass() == 0f))
        return ;
    rv = TekVector2f.sub(bodyB.velocity, bodyA.velocity);
    normalVelocity = rv.dot(normal);
    if (normalVelocity > 0)
        return ;
    e = Float.min(bodyA.material.restitution, bodyB.material.restitution);
    j = -(1 + e) * normalVelocity;
    j /= bodyA.getInvMass() + bodyB.getInvMass();
    impulse = TekVector2f.scale(normal, j);
    bodyA.velocity.sub(TekVector2f.scale(impulse, bodyA.getInvMass()));
    bodyB.velocity.add(TekVector2f.scale(impulse, bodyB.getInvMass()));
    correction = TekVector2f.scale(normal, Float.max(penetrationDepth - 0.001f, 0.0f)/ (bodyA.getInvMass() + bodyB.getInvMass()) * 0.8f);
    bodyA.transform.position.sub(TekVector2f.scale(correction, bodyA.getInvMass()));
    bodyB.transform.position.sub(TekVector2f.scale(correction, bodyB.getInvMass()));
}

Edit: Updated code to make it easier to read

\$\endgroup\$
1
\$\begingroup\$

What you have stumbled onto is an extremely common problem in physics: The three body problem (though it's slightly different in real world physics).

There are a couple of solutions to this I'm aware of:

  1. Post-impulse correction. This requires you re-iterating over the bodies after applying impulses, and correcting any remaining intersections.

Pro: relatively simple to code (repeat narrow phase)

Con: It's expensive and doesn't guarantee the problem will be fixed.

  1. Normal force computation: compute an additional "normal" force, designed to push objects apart, regardless of their velocities. The strength of the force is dependant on penetration depth.

Pro: cheap (computationally speaking. It's only an extra couple of lines of code.

Con: It might make your objects behave a little weird in extreme cases, for example, make them fly up so fast they never come back down.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer! Regarding normal force computation, the tutorial I followed had it implemented and it seemed to be working fine on the author's project which leads me to think that I have a mistake somewhere in my code which I am unable to find. If you have any insight on this please let me know! \$\endgroup\$ – Bassintag Dec 11 '16 at 20:44
  • \$\begingroup\$ @Bassintag Looking at your code, I see no references to body density, which usually is factored into the normal force equation as a scalar quantity (mass is also calculated as a result of density * volume). It would help others to read your code, by commenting it, and also link the original tutorial. \$\endgroup\$ – Ian Young Dec 13 '16 at 1:29
  • \$\begingroup\$ I linked the original tutorial at the top of the post: gamedevelopment.tutsplus.com/tutorials/…, also I made my code cleaner and easier to read. I'll update it on the main post asap \$\endgroup\$ – Bassintag Dec 14 '16 at 14:50
  • \$\begingroup\$ Yes, I've read that tutorial before. It doesn't cover the stacking body problem, though it does mention slop, which is the minimum penetration distance allowed before the normal force is applied. The concept is this: The harder two bodies push together, the harder they push apart, due to their inherent "solidness". If every body is treated as equally and completely solid, then the calculation is thus: J = -(1+e) * (1+max(slop,penetrationDepth)) * normalVelocity; I'm doing this from memory, experiment with the value of slop, and let me know how it turns out. \$\endgroup\$ – Ian Young Dec 15 '16 at 17:14
  • \$\begingroup\$ Sorry for the late reply, I've been very usy with school projects and christmas, I tried experimenting with what you told me however it doesn't seem to change much. Bodies are still entering each other without being pushed away. I also tried looking at box 2D source but I can't manage to figure out what part of the code is making it work so well with many bodies. \$\endgroup\$ – Bassintag Dec 26 '16 at 0:15
0
\$\begingroup\$

I can suggest Baumgarte Stabilization

try adding a bit of energy in your impulse calculation

b = beta*penetrationDepth; 
j = -(1 + e) * normalVelocity + b;

And beta is a "small" constant : "Erin Catto proposed that you start increasing the value from 0 until your physics system starts to become unstable, and then use half that value."

\$\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.