Maths · function
dampTracking
Exponential approach of a toward a target that is itself moving, at velocity.
Explained in Coordinates and units.
function dampTracking(a: number, b: number, velocity: number, lambda: number, dt: number): numberimport { dampTracking } from '@driftengine/core';Parameters
| Parameter | Type | Description |
|---|---|---|
a | number | |
b | number | |
velocity | number | |
lambda | number | |
dt | number |
In depth
damp above is lerp(a, b, 1 - exp(-lambda dt)), which is the exact solution of
a' = lambda (b - a) for a b that holds still across the interval — a zero-order hold. For a
target that is moving it is wrong in two ways that both show up as the frame rate changes,
because the error is a function of dt:
- the settled gap becomes
v dt (1-k)/kfork = 1 - exp(-lambda dt), which shrinks as the frame time grows, so a machine that drops rate quietly re-frames the shot; - and under uneven frames the gap oscillates rather than settling at all.
This solves the same equation for b(t) = b - v (dt - t), a target arriving at b having
travelled at v. Substituting e = a - b gives e' = -lambda e - v, whose solution is
e(t) = (e0 + v/lambda) exp(-lambda t) - v/lambda — so the settled gap is v/lambda at every
rate and there is nothing left for jitter to move. b is the target now, at the end of the
interval, which is what a caller has.
What it costs is a velocity the caller has to supply, and a caller that passes zero gets
damp back exactly. A finite difference of the target over the frame is the usual source and is
exact for a target that is moving smoothly; what it is not good for is a target that steps,
where one frame of delta/dt is a spike and this will aim v/lambda ahead of it.
Zero or negative lambda returns a rather than dividing by it. The limit as lambda goes to
zero is a — no pull, no movement — so the guard agrees with the arithmetic rather than merely
avoiding an infinity.