(Original Image by Valerie Everett)
It is sometime necessary to move an object in a physics simulation to a specific point. On the one hand, it can be difficult to analyse the exact force you have to apply; on the other hand it might not look so good if you animate the object’s position directly.
A compromise that works well in many situations is to use a spring-damper system to move the object.
The trick is simple: we apply two forces—the one is proportional to the displacement; the other is proportional to the velocity. Tweaked correctly, they combine to give realistic movement to the desired point.
The spring force is proportional to the difference between the current position and the position where we want the object:
F_s = -k(x - x_0)Here, k is a positive value called the spring constant.
As you can see, the force gets smaller as our object approaches the desired position, and becomes zero when it reaches that position. Unfortunately, in the absence of friction or drag, the velocity is not zero at this point, so the object overshoots the desired position, and moves past it. The force becomes bigger, but in the opposite direction. The object keeps on moving, slowing down, and finally starts moving in the opposite direction towards the desired position. This goes on indefinitely.
When there is friction or drag, we might be lucky enough for the system to slow down the object sufficiently so that its velocity becomes zero when the object reaches the desired position. This can be tricky to accomplish, though, and might impact the simulation environment in undesirable ways.
It is better to add a counteracting force explicitly. We add a damper force that is propostional to the velocity of the object, again opposite in direction. Here c is the viscous damping coefficient, also a positive number.
F_d = -cvWe then apply the sum of the forces to our object:
F_t = F_s + F_dThe trick is to choose c to get the behaviour we want.
Fortunately, this is easy. The following table summarizes how the damping constant affects behaviour. Here, m is the mass of the object.
c = 0 | The object oscillates. |
0 < c < 2\sqrt{mk} | The object oscillates, but the oscillations die down. |
c = 2\sqrt{mk} | The object moves to the desired position without oscillating in minimum time. |
c > 2\sqrt{mk} | The object moves to the desired position without oscillating, and takes longer as c increases. |
If you want to see an explanation of how this works, see the Wikipedia article on damping.
By choosing c = 2\sqrt{mk}, we are left with only one parameter to tweak (the spring constant), with which we can adjust the time it will take for the object to reach the desired spot.
A simple implementation of this idea is given by the following function. The function should be called for every simulation frame, until we are satisfied that the object reached its spot:
private void MoveTo(Rigidbody rigidbody, Vector3 newPosition, float springConstant) { Vector3 desiredDisplacement = rigidbody.position - newPosition; Vector3 springForce = -springConstant * desiredDisplacement; float viscousDampingCoefficient = 2 * sqrt(rigidbody.mass * springConstant); Vector3 dampingForce = -viscousDampingCoefficient * rigidbody.velocity; Vector3 totalForce = springForce + dampingForce; rigidbody.AddForce(totalForce); }
This will work even when there is drag or friction, except that the object will move slower (in this case we can decrease the artificial damping, although it is a bit risky). When there is an external force applied to the object, the object will come to rest at some point away from the desired position. By increasing the spring constant, the distance between this point and the desired point can be made smaller. Thus, we can also use this scheme to maintain objects at a certain height, for example, which can give a rather realistic simulation of a hovercraft or even a drifting object.
Update: This is an example of a PID controller (proportional–integral–derivative controller), for which there is a C++ implementation in my Special Numbers Library.
PID controllers, in other words.
Yes, I haven’t thought of it that way, but of course you are right.
Nice article!
Just to mention that if the target position is also moving and it’s moving away from the rigid body, you’ll want to dampen less, and likewise when it’s moving towards the rigid body, you’ll want to dampen more.
In other words, the velocity in the damping term should actually be *relative* velocity, and not just the velocity of the rigid body in isolation.
I’ve found this distinction quite important for camera systems and tractor beams where target positions are often relative to some other moving object.