- Home /
Why is the "t" value clamped to [0, 1] in Lerp functions?
Just for curiosity sake. Is there a reason why most (if not all) Lerp functions in Unity only take in [0, 1] as the range for t to interpolate? Are there performance issues related?
You are interpolating, so going from one position (current) to another position (target), the t is the ratio of movement you want to apply, most like a percentage 1 being full movement so 100% of it.
There is no reason to move more that the full distance, if one wanted to use 2 so that the target is twice as far, then it means the target is not meant to be the current target .
current = Type.Lerp(current, target, 2f);
target = current + (target - current) * 2f;
Those are quite similar if not identical.
Also, since you are interpolating, providing a value greater than the full movement means you are jumping there so there is no real reason of using a lerp there. Just like:
current = Type.Lerp(current, target, 1f);
is the same as:
current = target;
With lerp you want to get a portion of a difference and return it.
As for performance - clamping it is more expensive compared to just doing an unclamped lerp
$$anonymous$$eanwhile there's a $$anonymous$$athf.LerpUnclamped function, which can be used if 't' value shouldn't get clamped.
Answer by Acegikmo · Apr 24, 2015 at 09:12 AM
In almost all cases, you don't want to overshoot/undershoot the t value. It is, however, occasionally useful.
Here's an unclamped Lerp, in which case values outside 0-1 would be extrapolation:
public static float Lerp( float a, float b, float t ){
return t*b + (1-t)*a;
}
Alternatively, a function where it's optional:
public static float Lerp( float a, float b, float t, bool extrapolate = false ){
if( !extrapolate )
t = Mathf.Clamp01( t );
return t*b + (1-t)*a;
}
As for performance, not clamping is more performant compared to clamping.
I guess it also makes sense that Lerp does [0, 1] - Lerp is really a jargon for "Linear Interpolation". That's a fair point.
Answer by Kiwasi · Apr 24, 2015 at 12:26 AM
This is to prevent unintended overshoot. The most common usage of lerp is to move something from a start state to an end state. Allowing values higher then 1 or lower then 0 would cause the result to be outside of the original start and end state.
Its pretty trivial to roll your own lerp function that will let you overshoot.
...and Lerp was around before Unity, and is generally never clamped. There are perfectly good reasons to use values outside of 0-1. So, agree, the clamp in Unity was specially added to idiot-proof it for the most common "walk to" uses.
The "idiot proof" point is fair. And yes I know it's trivial to roll an unbounded lerp - I have done that already. Just wondering about the design decisions.
Answer by Eric5h5 · Apr 23, 2015 at 11:28 PM
Since it's a percentage, only the 0.0 to 1.0 range makes any logical sense. It takes (a tiny bit) of extra CPU time to clamp the value to that range.
Sorry, but from a mathematical perspective, that is nonsense.
For a start, it's not a percentage it's a proportion. If it was a percentage, the range would be 0-100.
Second, there's no reason whatsoever that percentages have to be in the range 0-100 (or proportions in the range 0-1).
There are plenty of times that I have wanted to be able to perform the same operation without restricting the domain of the proportion. Of course, it's a very simple calculation so implementing ones own function to do the job is trivial.
There is a semantic argument, in that interpolation is defined as estimating unobserved values within the range of of the observed data (strictly speaking, if your unobserved point is outside the observed domain then the operation is called "extrapolation"). So one could argue that Lerp is short for "Linear Interpolation" and so is only defined within the range of the boundary points passed in. But I$$anonymous$$O semantic arguments are considerably less whel$$anonymous$$g than practical ones.
Personally, I think the clamping is overkill on the part of the language developers. They've made too big an assumption about what the function is going to be used for; and while the clamping may only be a small overhead, if one is using it a lot then it ought to be the users' choice as to whether to accept that overhead. Often, one knows that the values one is passing in are in range anyway because of how they have been arrived at (you might for example want to check the values in a debug build but not in a production build).
I have experience of this issue, writing image analysis software for a space telescope. The image library provided to me was riddled with unnecessary bounds checks which slowed the software down to an absurd level. Implementing my own low-level functions ins$$anonymous$$d of using the ones in the library speeded processes up by orders of magnitude. So I would say that yes, there can definitely be significant performance implications, and doing your own check-free interpolation can definitely be beneficial.
So I$$anonymous$$O clamping, if required, should have be left to the client (or at least made optional with an extra parameter). But it's not such a hardship to have to write ones own code to get around the problem.
I think going to great lengths to differentiate between the range 0-1 and 0 to 100% constitutes nitpickery. :) From a computational standpoint, I'd much rather simply define 0-100 percent to be the range 0-1, because floats have higher precision in that range.
The second point you make is exactly why Eric is right that lerping outside the 0-1 bound makes no logical sense, except that it's not just a semantic argument - it IS a practical one. Observe that lerping is not just defined for vectors and floats, it's defined for colors too. (Color.Lerp). If I supply black and white as the endpoints, what do you suppose Color.Lerp should return if I pass in t = 2? Do you want "twice as white" to be returned, then? What if it's Color32.Lerp? The channels in that struct are bytes, so t = 1 would return 255,255,255. Should t = 2 then throw an overflow exception as it tries to store "510" in a byte, or do you want it to loop back around? In any case, there is no practical benefit from any of those, because the video card is going to clamp all colors to the range at the shader level anyway. This is not the only example, there are several cases where not clamping would be highly impractical. Another example could be timed animation. You never want interpolation into an animation using a number of miliseconds to return something less than 0 or greater than 1. What would that mean? What animation frame resides at 110%?
Implementing other Lerp methods so they exhibit similar behaviour is at least consistent, and I have never encountered a case where I truly did want to interpolate beyond 0 and 1.
Yes, interpolating between colours is a good example of a case where one would normally want to clamp to the bounds. Your experience is clearly different; in my own (using different kinds of domains), not wanting it clamped has been far more common. And like I said, the performance implications can be very significant and it can happen that the process you have used to deter$$anonymous$$e the interpolation variable for your colour or animation means that you already know it is within the required bounds. So it is useful for people to know that Unity's Lerp function is deliberately inefficient for the purpose of idiot-proofing and that if you're not an idiot, you can make things work faster.
I agree that the percentages/fractions/proportions thing is a kind of pedantry. It's a bugbear of $$anonymous$$e; I like to resist the tendency for words with perfectly good and precise meanings to lose their meanings, and that is happening with the word "percentage". In scientific papers, one does not generally get away with calling a proportion a percentage, and rightly so because people who know what the word means will take a "percentage" of 1 to represent a very small proportion.
Even with colors it occasionally makes sense to overshoot. Shaders aren't limited to the 0-255 range (Which, essentially would be the 0-1 range on a shader level).
If you're doing HDR rendering, colors can overshoot, which is then used for tonemapping. It's only clamped at the very end, not for every operation.
That's not entirely true. The COLOR semantic clamps the range in shaders, at least for vertex colors. Reading them from any of the appdata structs behaves like this. (Source: http://forum.unity3d.com/threads/vertex-color-is-clamped.140895/)
Your answer
Follow this Question
Related Questions
How do you Lerp light.color into multiple colors? 2 Answers
How the heck does Mathf.Lerp work? 2 Answers
Moving two game objects in To and Fro motion continuously? 2 Answers
Can't figure out how Time.deltaTime can works in this case 2 Answers
Line drawing: How can I interpolate between points to create a smooth arc? 4 Answers