change between colors over time

I'm trying to fade a fill, back and forth between two colors or cycle through three colors. I was able to fade from one color to the next, but I don't know how to make it go back or cycle through three colors.

float easing = 0.01;
float xRed = 62, xGreen = 20, xBlue = 173;
float yRed = 207, yGreen = 1, yBlue = 106;
float rDiff, gDiff, bDiff, avgDiff;

void setup() {
 size(500, 500);
}

void draw() {
  background(0);

  rDiff = dist(0, xRed, 0, yRed);
  gDiff = dist(0, xGreen, 0, yGreen);
  bDiff = dist(0, xBlue, 0, yBlue);
  avgDiff = (rDiff + gDiff + bDiff) / 3;

  if(avgDiff > 1) {
  xRed += (yRed - xRed) * easing;
  xGreen += (yGreen - xGreen) * easing;
  xBlue += (yBlue - xBlue) * easing;

  fill(xRed, xGreen, xBlue);      
  ellipse(width/2, height/2, 300, 300);
  }

}
Tagged:

Answers

  • That's a complex sketch. Instead, you could use lerpColor().

  • Yeah, I tried this:

    fill(lerpColor(colorA, colorB, (millis()%5000)/5000.0));

    But it only fades from colorA to colorB then jumps back to colorA again. I'd like it to fade back.

  • No I just said it because your sketch would look better then. That's it.
    The solution itself is different. I haven't tested, but this should work - lerpColor(colorA, colorB, ((millis()/5000)%2==0)?millis():5000-millis()).

  • No dice, just flips back and forth between the two colors, no fading.

  • Oops. I made a mistake, forgot the /5000.0 in my code.
    Try this - lerpColor(colorA, colorB, (((millis()/5000)%2==0)?millis():5000-millis())/5000.0)

  • Now, it fades from colorA to colorB at the start. Then jumps back to colorA without a fade. Then only jumps back and forth between them.

  • Example working with two colors. For three colors, you need to choose two colors at the time and use it with the code below.

    Kf

    float xRed = 62, xGreen = 20, xBlue = 173;
    float yRed = 207, yGreen = 1, yBlue = 106;
    
    boolean backwards=false;
    int timeLapse=2000;
    int timeTrack;
    
    
    void setup() {
      size(500, 500);
      timeTrack=millis()+timeLapse;
    }
    
    void draw() {
      background(0);
    
      //Next inverts diretion  
      if (millis()>timeTrack) {
        timeTrack=millis()+timeLapse;
        backwards=!backwards;
      }
    
      float per = (timeTrack-millis())/float(timeLapse);  
      if (backwards==true){  per = 1-per;}
      surface.setTitle(nf(per*100, 3, 2)+"% Flag="+backwards);
      fill(lerpColor(color(xRed, xGreen, xBlue), color(yRed, yGreen, yBlue), per));
      ellipse(width/2, height/2, 300, 300);
    }
    
  • Then maybe this should work - lerpColor(colorA, colorB, (((millis()/5000)%2==0)?millis()%5000:5000-millis()%5000)/5000.0)

  • @mHoneycomb --

    Here's a simple example of a class that handles timed color fading.

    Create a single object and flip the color back and forth, or update the target color periodically, or update or replace the whole thing with a new object using a new set of colors / times.

    /** Press any key to fade to a new random color **/
    
    FadeColorTimer fc;
    
    void setup(){
      // start black, fade to red by starting at 4 secs and transitioning for 1.5 secs
      fc = new FadeColorTimer( color(0, 0, 0), color(255,0,0), 4000, 1500);
      textAlign(CENTER,CENTER);
    }
    
    void draw(){
      background(0);
      fill(fc.c()); // use current color
      rect(10,10,80,80);
      fill(255);
      text(fc.text(), width/2,height/2); // show text of color color
    }
    
    void keyReleased(){
      color cr = color(random(255), random(255), random(255));
      // change the target color to a random color (and restart timer)
      fc.set(cr);
    }
    
    
    /**
     * FadeColorTimer is a timer object that contains two colors
     * interpolated by lerpColor().
     * Instantiate with two colors, a start time, and a duration.
     * c() returns the current interpolated color value
     * set() updates the color, colors, and/or timer.
     **/
    
    class FadeColorTimer {
      color c1, c2, c;
      int start, duration;
      FadeColorTimer(color _c1, color _c2, int _start, int _duration){
        c = _c1;
        c1 = _c1;
        c2 = _c2;
        start = _start;
        duration = _duration;
      }
      void set(color _c2){
        set(c, _c2, millis(), duration);
      }
      void set(color _c2, int _duration){
        set(c, _c2, millis(), _duration);
      }
      void set(color _c2, int _start, int _duration){
        set(c, _c2, _start, _duration);
      }
      void set(color _c1, color _c2, int _start, int _duration){
        c1 = _c1;
        c2 = _c2;
        start = _start;
        duration = _duration;
      }
      void update(){
        println(c1, c2, map(millis(), start, start+duration, 0.0, 1.0));
        c = lerpColor( c1, c2, map(millis(), start, start+duration, 0.0, 1.0));
      }
      color c(){
        this.update();
        return c;
      }
      String text(){
        String[] str = {
          str((int)red(fc.c)),
          str((int)green(fc.c)),
          str((int)blue(fc.c))
        };
        return join(str, ',');
      }
    }
    
  • An overkill man....

  • edited March 2017

    Well, a demo. :)

    You can do a lerp in a line of code -- with a hand full of global variables -- and then put bits of control code here and there. As you face new challenges (reversing the colors, restarting the sequence, using three colors, or more, etc.) you can add new bits of control code here and there.

    Or you can take the class / object approach, wrapping anything you want it to do in an object. Now you have a lot of class code -- if you create multiple constructors, it gets really verbose! But once you have written that class you can do any of those things you wanted to do in draw, simply, in a line or two.

    Here's a more bare-bones version:

    class FadeColorTimer {
      color c1, c2, c;
      int start, duration;
      FadeColorTimer(color _c1, color _c2, int _duration){
        c1 = _c1;
        c2 = _c2;
        start = millis();
        duration = _duration;
      }
      color c(){
        c = lerpColor( c1, c2, map(millis(), start, start+duration, 0.0, 1.0));
        return c;
      }
    }
    
  • You guys are awesome! Thanks so much.

    @Lord_of_the_Galaxy Your code is so concise! It's a good reminder that I can always clean house a bit if I take the time. High level stuff!

    @jeremydouglass I only just started learning to code so it's great to see a complex sketch I can dig into and learn from. Great to have more room to throw new controls into, like you said as well.

    Thanks again, both of you!

    Oh, btw, I managed to make something that works using a sin wave haha. Of course, I knew it was inefficient so it's nice to see more proper code.

    float colorAngle = 0.0;
    
    float xRed = 62, xGreen = 20, xBlue = 173;
    float yRed = 207, yGreen = 1, yBlue = 106;
    
    float redX = xRed, greenX = xGreen, blueX = xBlue;
    float speed = 0.02;
    
    void setup() {
     size(500, 500);
    }
    
    void draw() {
      background(0);
      fill(redX, greenX, blueX);
    
      float sinval1 = sin(colorAngle);
      println(sinval1);
      redX = map(sinval1, -1, 1, xRed, yRed);
      greenX = map(sinval1, -1, 1, xGreen, yGreen);
      blueX = map(sinval1, -1, 1, xBlue, yBlue);
    
    
      ellipse(width/2, height/2, 300, 300);
      colorAngle += speed;
    
    }
    
  • edited March 2017

    I could probably make that into a single line too. I'll try today.
    And done- lerpColor(colorA, colorB, (sin(colorAngle+=speed)+1.0)/2.0)

  • edited March 2017

    @Lord_of_the_Galaxy what is the ? doing in (((millis()/5000)%2==0)?millis()%5000:5000-millis()%5000)/5000.0)

Sign In or Register to comment.