12
\$\begingroup\$

I have found it rather difficult to find a solution to this in the Unity documents.

Color.Lerp(Color a, Color b, float t) is a function that gradually changes a color according to a step t, giving it the final value of the Color b.

How do I Lerp between multiple colors one after another?

\$\endgroup\$
13
\$\begingroup\$

Let _colors be an array of colors let LENGHT be the number of colors in the array let t be the 0..1 float value

float scaledTime = t * (float) (LENGHT - 1);
Color oldColor = _colors[(int) scaledTime];
Color newColor = _colors[(int) (scaledTime + 1f)];
float newT = scaledTime - Mathf.Round(scaledTime); 

finally you can use Lerp

Color.Lerp(oldColor, newColor, newT)
\$\endgroup\$
  • \$\begingroup\$ +1 - great answer - doesn't require any looping or special branches, and is completely general to N colors. \$\endgroup\$ – jpaver Apr 21 '15 at 7:22
  • \$\begingroup\$ When the value 1 is hit will the color be the very last color in the array? \$\endgroup\$ – G3tinmybelly May 24 '15 at 22:10
  • \$\begingroup\$ G3tinmybelly you're right. The t==1 is not managed correctly. So we may add before : if (t==1) return Arr[N-1] \$\endgroup\$ – dnk drone.vs.drones May 25 '15 at 6:57
10
\$\begingroup\$

One approach that can be taken with multiple color transitions is to leverage a Gradient.

By exposing a public variable of this type a developer an use the Inspector to launch the Gradient Editor to design a gradient containing any number of colors. This editor allows you to use a the unity color pickers, fine tune placement of the color/alpha keys and save/load gradients.

enter image description here

Once designed the Gradient.Evaluate() method will accept a float in the range 0-1 to return the appropriate color.

using UnityEngine;

public class GradientTest : MonoBehaviour
{
    public Gradient myGradient;
    public float strobeDuration = 2f;

    public void Update() {
        float t = Mathf.PingPong(Time.time / strobeDuration, 1f);
        Camera.main.backgroundColor = myGradient.Evaluate(t);
    }
}

Unfortunately the API for programmatically building a Gradient is not as elegant .

\$\endgroup\$
  • 1
    \$\begingroup\$ ColorBands can be used for the same goal but with more freedom over color \$\endgroup\$ – SteakOverflow Aug 24 '16 at 14:02
1
\$\begingroup\$
public float every;   //The public variable "every" refers to "Lerp the color every X"
float colorstep;
Color[] colors = new Color[4]; //Insert how many colors you want to lerp between here, hard coded to 4
int i;
Color lerpedColor = Color.red;  //This should optimally be the color you are going to begin with

void Start () {

    //In here, set the array colors you are going to use, optimally, repeat the first color in the end to keep transitions smooth

    colors [0] = Color.red;
    colors [1] = Color.yellow;    
    colors [2] = Color.cyan;
    colors [3] = Color.red;

}


// Update is called once per frame
void Update () {

    if (colorstep < every) { //As long as the step is less than "every"
        lerpedColor = Color.Lerp (colors[i], colors[i+1], colorstep);
        this.GetComponent<Camera> ().backgroundColor = lerpedColor;
        colorstep +=0.025f;  //The lower this is, the smoother the transition, set it yourself
    } else { //Once the step equals the time we want to wait for the color, increment to lerp to the next color

        colorstep = 0;

        if (i < (colors.Length - 2)){ //Keep incrementing until i + 1 equals the Lengh
        i++;
        }
        else { //and then reset to zero
            i=0;
        }
    }
}

So this is the code I ended up using to lerp between three colors of mine, I hope I will be of use to anyone who decides to look for this.

\$\endgroup\$
0
\$\begingroup\$

I feel like there may be a better solution. The only reason I would see to lerp from color to color is if you were wanting to continuously change the hue... http://en.wikipedia.org/wiki/Hue

Here's how to convert HSV to RGB: http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV

With this you can use HSV colors, simply change the hue, then convert to RGB. Besides, with Color.Lerp, you have the problem of inconsistency. If you lerp from orange to yellow, then to green, you'll find that the color starts to go to yellow very quickly then starts to slow as it nears yellow, then speeds up again once it passes yellow and goes to green. So it will slow color changing at every point that you're lerping to. I think changing the hue would be much more effective - and in the long run, will give a better effect. :)

\$\endgroup\$
0
\$\begingroup\$

How about you write your own version, which leverages Color.Lerp()?

A very simple version that takes 3 colors, and puts the second one right in the middle could look like this:

Color Lerp3(Color a, Color b, Color c, float t)
{
    if (t < 0.5f) // 0.0 to 0.5 goes to a -> b
        return Color.Lerp(a, b, t / 0.5f);
    else // 0.5 to 1.0 goes to b -> c
        return Color.Lerp(b, c, (t - 0.5f) / 0.5f);
}
\$\endgroup\$
0
\$\begingroup\$

Since you didn't say what you wanted to change color to, I'll give a vague example with a color created on the method.

The point is to have a collection of the colors, and a duration in total (like on the example I'll provide) or a duration between each one (that's up to you).

I personally do not interpolate things on Update that I know I won't be constantly interpolating (Camera being an exception), so I use coroutines to handle that.

On this example I divide the duration given on inspector by the colors quantity, and then I Lerp the actual iterator color to the next iterator color, and the duration will be of the duration previously spliced. Here is the sample:

public class ColorLerping : MonoBehaviour
{
    public Color sampleColor; /// Just for debugging purposes.
    public float lerpDuration;
    public Color[] colors;

    void Awake()
    {
        StartCoroutine(LerpColors());
    }

    private IEnumerator LerpColors()
    {
        if(colors.Length > 0)
        {
            /// Split the time between the color quantities.
            float dividedDuration = lerpDuration / colors.Lenght;

            for(int i = 0; i < colors.Length - 1; i++)
            {
                float t = 0.0f;

                while(t < (1.0f + Mathf.Epsilon))
                {
                    sampleColor = Color.Lerp(colors[i], colors[i + 1], t);
                    t += Time.deltaTime / dividedDuration;
                    yield return null;
                }

                // Since it is posible that t does not reach 1.0, force it at the end.
                sampleColor = Color.Lerp(colors[i], colors[i + 1], 1.0f);
            }

        }
        else yield return null; /// Do nothing if there are no colors.
    }
}

Hope it helps.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.