12
\$\begingroup\$

I've got a simple physics engine that solves collisions by simply correcting the position of overlapping bodies (just circles for now) directly, as opposed to just changing the velocity or applying an impulse. Velocity is only changed after impacts are already resolved, or during the integration part.

I've had the problem that in heaps of objects the top objects apply too much pressure (this exists implicitly, there's no pressure modelling in the algorithm) on the objects at the bottom of the heap, which results in them getting pushed through floors, etc.

I wanted to fix this by sorting the objects by their y-coordinate, so the collisions are resolved bottom-up. But now, the engine shows weird popping behavior for objects which should actually be at rest (see gif)

enter image description here

Without just giving you the source code - what could this be?

\$\endgroup\$
4
  • 5
    \$\begingroup\$ All in all, this is similar to solving a linear system of equations in an iterative manner (or nonlinear system, depending on your constraints/conditions/etc). Either case, you're seeing these artefacts because they're numerically the correct thing to see: intermediate states of a converging process. Avoiding this is quite tough and could imply a lot of nasty hacks (anyway, this happens in real life, at a molecular level, and that's what you have there to best resemble something in real life :) ). It's probably good to investigate box2d to see their solution for impulse based dynamics. \$\endgroup\$
    – teodron
    Apr 17, 2013 at 7:54
  • \$\begingroup\$ @TravisG how did you solve the problem? I'm looking at a similar problem when trying to implement a very simple physics engine. \$\endgroup\$ Dec 12, 2013 at 19:24
  • 1
    \$\begingroup\$ @cheeesus It's been a while since I worked on it, but I believe I just used more iterations with smaller timesteps. \$\endgroup\$
    – TravisG
    Dec 12, 2013 at 19:41
  • \$\begingroup\$ There's a related answer here about nudging physics bodies into "sleeping" states which might be useful. \$\endgroup\$
    – DMGregory
    Sep 12, 2017 at 11:18

3 Answers 3

6
\$\begingroup\$

One solution I have found when using position correcting is to have a few iterations and vary the strength with each iteration.

doPhysics();

int num_iterations = 5;
for(int iteration=0; iteration<num_iterations; ++iteration)
{
    float strength = float(iteration+1)/num_iterations;
    correctPositions(strength);
}

So the first iteration has a strength of 1/num_iterations and the last has a strength of 1. This makes my simulations smoother and more stable than simply using the same number of iterations with a fixed strength.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Nice solution, but why does it work? \$\endgroup\$ Mar 26, 2017 at 19:12
  • \$\begingroup\$ This works really well, but the iterations needs to keep increasing with larger numbers of bodies. \$\endgroup\$
    – silverfox
    Jun 6, 2022 at 10:59
5
\$\begingroup\$

Your problem lies in the fact that you have no "resting" state for your bodies. Any physics system has an amount of energy, be that kinetic, thermal, and so on. In reality, solid object deform slightly, and tranform some kinetic energy into heat, though it is hardly measurable. It's also worth noting that in reality there is no such thing as a completely solid object. Even dense materials, like diamond, have space in between the atoms, giving the atomic structure room to flex, and absorb kinetic energy.

To make this relevant, resting bodies are in a state where the only forces in effect is the "normal force", which is to say, the force that prevents bodies from floating through each other. The magnitude of that normal force, is proportional to the density of the objects, and how far they have penetrated each other.

Physics engines call this value "slop".

Here's the trick: Calculate the slop, and correct the position of the bodies, and apply the normal force, based on the relative velocity of the two bodies. during the update of the bodies themselves, calculate the kinetic energy of each body. If it is below a minimum value, then put the body to sleep, until a force of sufficient magnitude is applied to it. (usually twice the minimum value).

\$\endgroup\$
0
\$\begingroup\$

Why not add a "sticky" surface to them and have them stick to a resting position gradually and when another object hits it it transfers some energy into it causing it to move but the sticky surface will cause it to lose some of this energy and stop in a resting position. the gif looks like it has no friction to it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .