TT Lab
Get started
Learn Learning paths Courses

The Skeleton of a Physics Engine

One Impulse and It Is Over

Continue in TT Lab

In one line

Collision response is computed not with force but with impulse. You solve for the value that changes the velocities in one go so that the two objects move apart, and apply it right away.

Why this was needed

To treat a collision with force, you would have to integrate the force during contact over time. But the contact time of hard objects is less than 1 millisecond, so in a simulation that runs at 1/60 second intervals that whole moment falls inside a single step. No matter how large you make the force, within one step the objects have already penetrated each other.

That is why a physics engine does not imitate the contact process and computes only the result. It sets up the relationship between velocities before and after the collision as an equation and finds the velocity change that satisfies it in one go. This change is the impulse, and its unit is force times time, that is, the same as momentum.

How it works

The key is the relative velocity of the two objects seen along the collision normal.

v_rel = dot(v2 - v1, n)        # n 은 1에서 2를 향하는 단위 벡터

If this value is positive, the two objects are already moving apart and you do nothing. If you leave out this check, you pull back an object that is already separating, and the object sticks to the surface.

If it is negative, you compute the impulse. The coefficient of restitution e is the value that decides how many times the relative velocity before the collision comes back after it; 1 means perfectly elastic (energy is conserved), and 0 means perfectly inelastic (they stick and move together).

j = -(1 + e) * v_rel / (inv_m1 + inv_m2)

v1 -= j * inv_m1 * n
v2 += j * inv_m2 * n

Here the convention is to use inverse mass rather than mass. Turning a division into a multiplication is a little faster, but the real reason is that an immovable object can be expressed naturally as inverse mass 0. If you put infinite mass in the code, every division needs special handling, but inverse mass 0 is just a number.

This computation always conserves momentum. It is structural, because the two objects receive impulses of equal magnitude and opposite direction. Kinetic energy, on the other hand, is conserved only when e is 1, and if it is smaller, that much disappears. In reality the lost energy goes into sound, heat and deformation.

Friction does the same computation once more along the tangent direction, but puts an upper limit on the magnitude.

t = normalize(v - dot(v, n) * n)      # 법선 성분을 뺀 나머지 = 접선 방향
jt = -dot(v, t) / inv_m               # 접선 속도를 0 으로 만드는 값
jt = clamp(jt, -mu * jn, +mu * jn)    # 쿨롱 마찰의 원뿔

You first find how much is needed to remove the tangential velocity completely, and if that value exceeds mu * jn, you clamp it. If it does not exceed it, the object stops on the spot (static friction), and if it does, only the clamped value is applied and it slides (kinetic friction). One conditional gives both frictions.

When rotation is included, the expression gets a little longer. This is because if the contact point is away from the center of mass, the impulse also produces rotation. Then terms coming from each object's moment of inertia are added to the denominator, and when applying the impulse you must change the angular velocity as well as the linear velocity. The structure is the same — find the relative velocity, solve for the impulse that makes it the value you want, and apply it. The reason this lab leaves out rotation is to let you see the skeleton of the expression first.

The coefficient of restitution is not a property of an object. It is a property of the combination in which two objects meet, and it also varies with the speed of impact. In practice people combine the values of two objects roughly, by multiplying them or taking the smaller one, and either way the physical basis is weak. Rather than struggling to get the value exact, it is better to choose a value that produces the feel you want.

What it looks like in the field

A common problem is an object that keeps bouncing at a low height and does not stop but trembles slightly. This is because, even if the coefficient of restitution is small, as long as it is not 0 the bouncing speed does not converge to 0. The practical fix is to force the coefficient of restitution to 0 when the relative velocity is smaller than some threshold.

Another is when there are several contacts at the same time. If you solve the contacts one at a time in order, the one solved later ruins the one solved earlier. That is why you solve repeatedly several times within the same step, and this is the subject of the next module.

Finally, let me point out once more the convention of signs and directions. Once you decide that the normal points from 1 to 2, the whole code must keep that convention. If the detection side returns it the other way, objects pull each other together instead of pushing apart, and the symptom shows up as "the objects stick and do not separate", so it is hard to guess the cause. That is why it is safer to pin down this convention between the detection function and the response function with a test rather than a comment.

What you will do in the next lab

You build the impulse formula yourself and check in numbers what happens to momentum and energy depending on the coefficient of restitution, and see in a graph that the height a ball bounces to shrinks by a factor of e² each time. Next, you find the distance at which a box sliding with Coulomb friction stops and compare it with the analytic answer, and finally you make five balls bounce inside a box and leave their trajectories in a picture.