Fade image in

edited February 2014 in How To...

So I am designing an app that displays a splash screen when first launched. In the draw function, I check the time and display the main screen at the appropriate time. Everything else is managed via mouseClicked. I want the home screen to fade in smoothly rather than just appear, but I cant seem to get it to work. I can get the transparency incrimination to work in a basic program with only that, but when I add that to my app, it doesn't fade; it still just appears. Below is my current attempt:

void draw() {
  // Check current time
  int currentMillis = millis() - startTime;
  // If running for more than 3 seconds...
  if ((currentMillis - previousMillis) > 2500 && firstLoop == true)
  {
    // Store current time
    previousMillis = currentMillis;
    // Display main screen
    for (int alpha = 0; alpha < 255; alpha +=2) {
      background(155);
      fadeIn(homeScreen, alpha);
    }
//    image(homeScreen, width/2, height/2);
    image(infoButton, 1000, 600);
    firstLoop = false;
  }
}

void fadeIn(PImage image, int alpha) {
//  background(155);
  tint(255,255, 255, alpha);
  image(image, width/2, height/2);
}

I have also tried putting the alpha for loop in the void fadeIn() and just using the for loop without the fadeIn(). Everything seems to just display the homeScreen at full opacity after the 2.5 seconds of the splash screen.

Answers

  • Remember that draw() renders the latest canvas state when it reaches its closing curly brace.
    Those lines 10 - 13 defeat the idea of using millis(). It invokes fadeIn() about 127 times!
    Its final result when draw() finishes gonna be alpha 253! (~~)

  • If I may suggest, use Ani library to have better control. Here's a short example fading the background from black to white:

    import de.looksgood.ani.*;
    
    float x = 0;
    
    void setup() {
      size(300,300);
      Ani.init(this);
    }
    
    void draw() {
      background(x);
    }
    
    void keyPressed() {
        Ani.to(this, 1.5, "x", 255);
    }
    
  • I want fadeIn() to run 127 times (or at least for alpha to increment 127 times. The point of millis() is to keep track of when the program started, and once a sufficient amount of time has passed, I want to change the image by fading the new one in. In theory, when line 5 is true, the for loop will run 127 times, each making the new image a little more opaque and eventually ending with the new image with no transparency. However, this does not happen: the new image just appears with no fading

  • edited February 2014

    However, this does not happen: the new image just appears with no fading.

    It does happen, inside the PGraphics buffer g, which represents Processing's canvas! /:)
    But repeating myself again, that buffer is actually rendered after draw() callback finishes!
    We only end up viewing its latest state. We don't see intermediary drawings within draw()! X_X

    We can even consider draw() as a big infinite loop, which delivers its result at the end of each of its rounds @ 60 FPS by default.
    If we wanna see some animation being drawn, we gotta do it in little steps at each draw(). Not everything at once! 3:-O

  • Ok. I misunderstood what you said. So now I can get the new picture to fade in (by taking out the for loop), but it only increments the alpha value every 2.5 seconds, even when I don't set previousMillis equal to currentMillis. That if statement should be returning true until the value of currentMillis wraps back to zero, correct? Why then is alpha stepping every 2.5 seconds?

      long currentMillis = millis() - startTime;
      // If running for more than 3 seconds...
      if ((currentMillis - previousMillis) > 2500 && firstLoop == true)
      {
        // Display main screen
        tint(255,alpha);
        image(homeScreen, width/2, height/2);
        image(infoButton, 1000, 600);
        alpha += 2;
        if (alpha >= 255)
          firstLoop = false;
          previousMillis = currentMillis;
      }
    
  • I figured it out, but maybe you can help explain why this worked.

    void draw() {
      // Check current time
      long currentMillis = millis() - startTime;
      // If running for more than 3 seconds...
      if ((currentMillis - previousMillis) < 2500 || firstLoop == false) {
        println(currentMillis-previousMillis);
        return;
      }
      // Display main screen
      tint(255,alpha);
      image(homeScreen, width/2, height/2);
      image(infoButton, 1000, 600);
      alpha += 2;
      if (alpha >= 255)
        firstLoop = false;
    //    previousMillis = currentMillis;
    }
    

    With line 16 uncommented, the value of currentMillis-previousMillis would reach 2500 and reset to 0, even when only run after alpha reached 255. When I take that out, it works perfectly. What caused the value to loop back?

  • edited February 2014 Answer ✓

    I dunno what previousMillis is for!? Function millis() constantly updates itself! You either use a startTime or a stopTime!
    What you really need is map() current millis() according to its DURATION time to the ALPHA range.

    Another alternative is use variable frameCount. It holds how many times draw() was auto-invoked.
    By default, draw() is called back @ 60 FPS. Hence each 60 frameCount means about 1 second.
    Let's say you wish the whole alpha process to take 5 seconds. So DURATION = 5*FPS. =:)

    Check it out my attempt frameCount + map() based version: >-)

    // forum.processing.org/two/discussion/3226/fade-image-in
    
    static final int FPS = 60, DURATION = 5*FPS; // 5 seconds animation.
    
    static final String URL = "http://" + 
    "upload.wikimedia.org/wikipedia/commons/9/9e/";
    static final String ARCHIVE = "Diqing,_Yunnan,_China.jpg";
    
    PImage picture;
    
    void setup() {
      size (800, 600, JAVA2D);
      frameRate(FPS);
      smooth(4);
      imageMode(CENTER);
    
      picture = loadImage(URL + ARCHIVE);  // online download.
      //picture = loadImage(ARCHIVE);  // local load.
    }
    
    void draw() {
      clear();
    
      //final int fc = frameCount;
      final int fc = frameCount % DURATION;
      final float opacity = map(fc, 0, DURATION, 0, 0400);
    
      tint(-1, opacity);
      image(picture, width>>1, height>>1);
    
      frame.setTitle("Alpha: " + round(opacity) + "\t\tTime: " + fc/FPS);
    }
    
Sign In or Register to comment.