Make perlin noise loop duration coincide with frame duration for looping GIF

Hello,

I didn’t wanna ask two questions in such a short time, but I’ve been having a doubt related to two videos by The Coding Train, “Polar Perlin Noise Loops” and “Perlin Noise GIF Loops”. I tried to mix the two but isn’t working as it should. I had some more problems here that I solved, but this one is giving me a hard time.

The first video is about using perlin noise to make distorted circles like these two, from this program:

The second is about counting the frames, making things happen in that interval and going back to the first frame. There’s a boolean value that, when false, lets things loop, and when true, it closes the program before the last frame, recording each one of them in images that can be used to create an animation. There is also a class to create looping noise values.

The problem here is, I think, that I have a for() loop to create the distorted circles (in each frame, for each vertex, I create a point and then create a shape with all of them). If I use the variable created inside the for() loop to define the noise values, then the shape works how I want it to, but when the final frame arrives and it goes back to the beginning, the skip is noticeable. I think the noise values are looping, but they don’t coincide with the frame duration.

If I use the variable “a” related to the frame duration for the noise values, then the shape gets really weird, moves really fast and I can’t control it. So, I think I have to make every loop’s end coincide.

I simplified the script to get it closer to the videos and to the basics and wrote some notes so it gets clearer.

Thank you!

int framesTotais = 200; //total frames
int contador = 0; //counter
boolean gravar = false; //if true it plays 1x and records. if false it loops forever
CirculoNoise c1 = new CirculoNoise(400, 180, 280); //the Noise Circles have their own class
CirculoNoise c2 = new CirculoNoise(2, 30, 160);
float velRot = 0.007; //rotation speed

void setup() {
  size(600, 600);
  background(0);
  noFill();
}

//the stuff to make the loop is here in the draw() function. there is a render() function where the drawing really happens
void draw() {
  float percentagem = 0; //porcent value goes from 0 to 1
  if (gravar) {
    percentagem = float(contador) / framesTotais;
  } else {
    percentagem = float(contador % framesTotais) / framesTotais;
  }
  render(percentagem);
  if (gravar) {
    saveFrame("output/"+day()+month()+year()+"_"+hour() + "/gif-"+nf(contador, 3)+".png");
    if (contador == framesTotais-1) { //last frame would be equal to the first
      exit();
    }
  }
  contador++;
}

void render (float percentagem) {
  background(0);
  translate(width/2, height/2); //draw noisy circles in center
  float a = percentagem * TWO_PI; //angle
  c1.render(a);
  c2.render(a);
}

class CirculoNoise {
  NoiseLoop xNoise, yNoise, zNoise, rNoise;
  float ampX, ampY, ampZ, raioMin, raioMax, zoff;

  CirculoNoise(float amp, float raioMin, float raioMax) {
    xNoise = new NoiseLoop(5, 0, amp);
    yNoise = new NoiseLoop(5, 0, amp);
    rNoise = new NoiseLoop(1, raioMin, raioMax);
  }

  void render(float a) {
    beginShape(); //the code below creates an ellipse by defining it's many points. it also changes each point's position with noise, creating distorted circles instead of simple circles
    rotate(a);
    stroke(255);
    for (float a2= 0; a2 < TWO_PI; a2+= TWO_PI/120) { //i think the problem is here, as i wrote in the post
      float xoff = xNoise.valor(a2);
      float yoff = yNoise.valor(a2); 
      float r =  rNoise.valor3D(xoff, yoff, a);
      float x = r*cos(a2); //x values for the circle's points
      float y = r*sin(a2); //y values for the circle's points
      vertex(x, y);
    }
    endShape(CLOSE);
  }
}

class NoiseLoop { //there is a circle looping in a 2D noise plane. the noise values are taken from the circle, repeating themselves constantly if necessary
  float diametro; //diameter
  float min, max;
  float cx, cy; //values for the circle's edge

  NoiseLoop(float diametro, float min, float max) {
    this.diametro = diametro; //the bigger the diameter, the bigger the interval between noise values
    this.min = min;
    this.max = max;
    cx = random(1000);
    cy = random(1000);
  }
  
  float valor(float a) {
    float xoff = map(cos(a), -1, 1, cx, cx+diametro); //x noise value
    float yoff = map(sin(a), -1, 1, cy, cy+diametro); 
    float r = noise(xoff, yoff);
    return map(r, 0, 1, min, max);
  }
  
    float valor3D(float xoff, float yoff, float zoff) { //i made this so i could have a 3D noise value for the noisy circle
    float r = noise(xoff, yoff, zoff);
    return map(r, 0, 1, min, max);
  }
}
2 Likes

My original code was a mess, I already have a new, simpler, better version that is working. My only doubt now is how to make the animation speed slower without changing the frame rate. But the problem asked here is solved.

1 Like

You can use Timesteps