lerp()
and fit()
are two functions you'll use constantly. They let you remap linearly, great for interpolation and extrapolation.
If you've ever wondered how they work, look no further. I remade them on my After Effects Fun page, so let's port them to VEX!
For a great resource on deriving them yourself, check out Simon and Freya's videos!
Lerp takes two values and does a weighted sum based on a factor.
For example to get halfway between two values, you'd add half of each:
0.5 * value1 + 0.5 * value2
To get 75% between two values, you'd add 1/4 of the first and 3/4 of the second:
0.25 * value1 + 0.75 * value2
Generalizing this gives the formula for lerp:
// Weighted sum
float lerp_diy(float value1; float value2; float amount) {
return (1 - amount) * value1 + amount * value2;
}
Or the imprecise version, which is shorter but suffers from floating point error:
// Imprecise version
float lerp_diy(float value1; float value2; float amount) {
return value1 + amount * (value2 - value1);
}
Inverse lerp takes a value and a range, then remaps the value so it lies between 0 and 1.
For example, say you have a value between 2 and 5. Start by moving the range so it starts on 0.
value - 2;
Now it lies between 0 and 3. To move it between 0 and 1, just divide it by 3 (the difference between 5 and 2).
(value - 2) / (5 - 2)
Generalizing this gives the formula for inverse lerp:
float invlerp_diy(float value; float min; float max) {
return (value - min) / (max - min);
}
It's a handy shorthand for fit(value, min, max, 0, 1)
.
fit()
is the combination of invlerp()
and lerp()
.
It can interpolate but can't extrapolate, because value
is clamped between omin
and omax
.
float fit_diy(float value; float omin; float omax; float nmin; float nmax) {
float normal = clamp((value - omin) / (omax - omin), 0, 1); // Inverse Lerp
return (1 - normal) * nmin + normal * nmax; // Lerp
}
// Lerp version
float fit_diy(float value; float omin; float omax; float nmin; float nmax) {
return lerp(nmin, nmax, clamp(invlerp(value, omin, omax), 0, 1));
}
// Imprecise version (rwaldron.github.io/proposal-math-extensions/#sec-math.scale)
float fit_diy(float value; float omin; float omax; float nmin; float nmax) {
return (clamp(value, omin, omax) - omin) * (nmax - nmin) / (omax - omin) + nmin;
}
efit()
is the same as fit()
, except value
isn't clamped.
This means it can interpolate and extrapolate value
outside of omin
and omax
.
float efit_diy(float value; float omin; float omax; float nmin; float nmax) {
float normal = (value - omin) / (omax - omin); // Inverse Lerp
return (1 - normal) * nmin + normal * nmax; // Lerp
}
// Lerp version
float efit_diy(float value; float omin; float omax; float nmin; float nmax) {
return lerp(nmin, nmax, invlerp(value, omin, omax));
}
// Imprecise version (rwaldron.github.io/proposal-math-extensions/#sec-math.scale)
float efit_diy(float value; float omin; float omax; float nmin; float nmax) {
return (value - omin) * (nmax - nmin) / (omax - omin) + nmin;
}
fit01()
is the same as fit()
except the range is hardcoded as 0 to 1. It's the same as lerp()
except value
is clamped between 0 and 1.
float fit01_diy(float value; float nmin; float nmax) {
float normal = clamp(value, 0, 1);
return (1 - normal) * nmin + normal * nmax; // Lerp
}
// Lerp version
float fit01_diy(float value; float nmin; float nmax) {
return lerp(nmin, nmax, clamp(value, 0, 1));
}
// Imprecise version
float fit01_diy(float value; float nmin; float nmax) {
return nmin + clamp(value, 0, 1) * (nmax - nmin);
}
fit01()
is the same as fit()
except the range is hardcoded as 1 to 0.
float fit10_diy(float value; float nmin; float nmax) {
float normal = clamp(1 - value, 0, 1);
return (1 - normal) * nmin + normal * nmax; // Lerp
}
// Lerp version
float fit10_diy(float value; float nmin; float nmax) {
return lerp(nmin, nmax, clamp(1 - value, 0, 1));
}
// Imprecise version
float fit10_diy(float value; float nmin; float nmax) {
return nmin + clamp(1 - value, 0, 1) * (nmax - nmin);
}
fit11()
is the same as fit()
except the range is hardcoded as -1 to 1.
float fit11_diy(float value; float nmin; float nmax) {
float normal = clamp(value * 0.5 + 0.5, 0, 1);
return (1 - normal) * nmin + normal * nmax; // Lerp
}
// Lerp version
float fit11_diy(float value; float nmin; float nmax) {
return lerp(nmin, nmax, clamp(value * 0.5 + 0.5, 0, 1));
}
// Imprecise version
float fit11_diy(float value; float nmin; float nmax) {
return nmin + clamp(value * 0.5 + 0.5, 0, 1) * (nmax - nmin);
}