0
\$\begingroup\$

I had a bit of a look around and couldn't see anywhere this was addressed, my apologies if it has been.

In Color.Lerp, I understand that the 3rd parameter t is not in fact the time that it takes to change between the colors but is rather the "blend factor". If the first color is at 0 and the second is at 1, then a blend factor of e.g. 0.2 would indicate it is closer to the first than the second.

My confusion is this - how exactly is it determined how long it takes the lerp to occur? I assume it's something to do with the frames per second? e.g. if the blend factor is 0.001 and frames per second are 50, with lerp in the update function then it should take 0.001 * 50 = 0.05 of a second for the change to occur?

\$\endgroup\$
1
  • \$\begingroup\$ There are two common patterns for using lerp: 1) current = lerp(start, end, progress) This one doesn't change the blended colour over time unless you manually increment progress. 2) current = lerp(current, target, sharpness) Note in form 2, current appears on both the left and the right side, so this version incorporates feedback from frame to frame and does change "on its own." It sounds to me like you might be asking about the second. Can you confirm, or share an example code snippet illustrating how you're using lerp? \$\endgroup\$
    – DMGregory
    Dec 19, 2017 at 18:26

2 Answers 2

3
\$\begingroup\$

The other answers correctly explain how the parameter works when you're using it something like this:

progress = Mathf.Clamp01(progress + Time.deltaTime/fadeDuration);
currentColor = Color.Lerp(startColor, endColor, progress);

But there's another common way to use Lerp that you might have seen (and your reference to a blend factor of 0.001 affecting the speed suggests to me that this might be the one you're using):

currentColor = Color.Lerp(currentColor, targetColor, sharpness);

This style is one we might call an Exponential Moving Average or Exponential Ease-Out. The change in colour starts quickly (if our sharpness were 0.5, we cover half the distance in the very first update), then gets slower and slower as we get closer to the target (our next updates move 1/4, 1/8, 1/16th of the original difference)

In pure math terms, this type of blend never actually finishes - it approaches the target asymptotically, but no finite number of iterations is enough to make currentColor equal to targetColor

On real computers, we have only finite precision, so the blend will eventually stop because the remaining difference rounds to zero (or is too small for the player to perceive).

For colours, we can estimate this time by figuring out how many iterations it would take to reduce an initial difference of 1.0f (the difference between full black and full white in colours normalized to the 0-1 range) to 0.5/255 (the smallest deviation from a colour that will round to a new 8-bit colour value for displaying on a conventional monitor)

$$\begin{align} (1 - sharpness)^{iterations} &= \frac 1 {2 \times 255}\\ iterations &= log_{(1 - sharpness)}\left(\frac 1 {510} \right) \\ iterations &= \frac {log\left(\frac 1 {510}\right)} {log(1 - sharpness)} \\ duration = iterations \times \text{frames per second} &= \frac {log\left(\frac 1 {510}\right)} {log(1 - sharpness)} \times fps \end{align}$$

So for your example of 0.001 for the sharpness parameter, it could take around 6200 iterations before the colour would stop changing, or around 124 seconds at 50 fps.

Granted, most of the change happens very quickly. Half the change happens in the first 14 seconds, and 95% of the change is done in the first minute. But exponential ease has a loooong tail. ;)

\$\endgroup\$
2
\$\begingroup\$

That's up to you and your needs.

Lerping can be based on time but it could also be used in order situations with other factors, for instance: how close is the player from the objective? You could want to lerp from red to green. In this case, the t parameter would be computed like such (pseudo-code):

departurePosition
endPosition
currentPosition

totalDistanceToGo = (endPosition - departurePosition).lenght
distanceLeftToGo = (endPosition - currentPosition).lenght

ratioDone = clamp(0, 1, distanceLeftToGo/totalDistanceToGo)

colourUsed = Color.Lerp(Color.red, Color.green, ratioDone);

If you need to lerp on time, you'd have to set in advance over what period you'd like to lerp, then use this value and the frame time to determine t (pseudo-code):

totalDurationInSec = 3
timeAccForLerp = 0
lerpedColour

function Update() {
   timeAccForLerp += Time.deltaTime
   timeAccForLerp = clamp( 0, totalDurationInSec, timeAccForLerp )
   lerpedColour = Color.Lerp(Color.red, Color.green, timeAccForLerp/totalDurationInSec);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .