Animated stripes gifs from scalar fields

This tutorial explains how to obtain this kind of GIF with Processing :

agif3.gif

We’ll start from this code that generates the following simple animation ;

int margin = 50;
int numFrames = 20;

void setup(){
  size(600,600);

}

float pixel_color(float x,float y,float t){
  float result = map(sin(TWO_PI*t),-1,1,0,1);
  return 255*result;
}

void draw(){
  background(0);

  float t = 1.0*(frameCount-1)%numFrames/numFrames;

  // Draws every pixel
  for(int i=margin;i<width-margin;i++){
    for(int j=margin;j<height-margin;j++){
      stroke(pixel_color(i,j,t));
      point(i,j);
    }
  }

  // Draws a white rectangle
  stroke(255);
  noFill();
  rect(margin,margin,width-2*margin,height-2*margin);

  // Saves the frame
  println(frameCount,"/",numFrames);
  saveFrame("frame###.png");

  // Stops when all the frames are rendered
  if(frameCount == numFrames){
    println("finished");
    stop();
  }
}

agif.gif

That code makes each pixel in a white rectangle oscillate between black and white over time. The rest will be only little variations from there so make sure you understand the basis.

Now let’s have moving stripes !
So let’s change the pixel_color function so that the color of pixels doesn’t oscillate at the same time vertically.

float pixel_color(float x,float y,float t){
  float result = map(sin(TWO_PI*(t+0.05*y)),-1,1,0,1);
  return 255*result;
}

agif2.gif

Now let’s make those stripes more contrasted. To achieve that we’ll use an easing function that makes values between 0 and 0.5 closer to 0 and values between 0.5 and 1 closer to 1, with a parameter g to increase the effect.

float ease(float p, float g) {
  if (p < 0.5)
    return 0.5 * pow(2*p, g);
  else
    return 1 - 0.5 * pow(2*(1 - p), g);
}

Let’s use it on our oscillating color :

float pixel_color(float x,float y,float t){
  float result = ease(map(sin(TWO_PI*(t+0.05*y)),-1,1,0,1),3.0);
  return 255*result;
}

This is the result :

agif3.gif

Now let’s make a general function that controls the offset in the oscilation :
(a scalar field is just a function that gives a real value for each position of the plane in our case)

float scalar_field_offset(float x,float y){
  return 0.05*x+0.05*y;
}

float pixel_color(float x,float y,float t){
  float result = ease(map(sin(TWO_PI*(t+scalar_field_offset(x,y))),-1,1,0,1),3.0);
  return 255*result;
}

Result (there is now horzontal change due to 0.05*x) :

agif4.gif

Now to obtain different results we just have to change the scalar field. Let’s use the distance to the center.

float scalar_field_offset(float x,float y){
  float distance = dist(x,y,width/2,height/2);
  return 0.05*distance;
}

agif5.gif

Perlin noise (a very nice function given by Processing, I won’t make a tutorial about it here) :

float scalar_field_offset(float x,float y){
  float scale = 0.003;
  float result = 40*noise(scale*x,scale*y);
  return result;
}

agif6.gif

Stripes and perlin noise gradually vertically :

float scalar_field_offset(float x,float y){ 
  float perlin_noise_intensity = pow(constrain(map(y,0.1*height,height,0,1),0,1),2);
  
  float scale = 0.006;
  float result = -0.05*y + 20*(noise(scale*x,scale*y)-0.5)*perlin_noise_intensity;
  return result;
}

agif7.gif :

Perlin noise in the center :

float scalar_field_offset(float x,float y){
  float distance = dist(x,y,width/2,height/2);
  float perlin_noise_intensity = ease(constrain(map(distance,0,0.3*height,1,0),0,1),2);
  
  float scale = 0.002;
  float result = -0.05*y -0.05*x + 60*(noise(scale*x,scale*y)-0.5)*perlin_noise_intensity;
  return result;
}

agif8.gif

Using distance differently :

float scalar_field_offset(float x,float y){
  float distance = dist(x,y,0.5*width,0.5*height);
  
  float result = 300/(25+distance);
  return result;
}

agif9.gif

By adding the effect of many centers you can get something like this :

tumblr_ouscz6fS6X1w3y4ilo1_500.gif

And with many centers and using an effect only near them :

agif.gif

Here is a complete code to generate one in case you missed anything :

int margin = 50;
int numFrames = 20;

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

float ease(float p, float g) {
  if (p < 0.5) 
    return 0.5 * pow(2*p, g);
  else
    return 1 - 0.5 * pow(2*(1 - p), g);
}

float scalar_field_offset(float x,float y){
  float distance = dist(x,y,0.5*width,0.5*height);
  
  float result = 300/(25+distance);
  return result;
}

float pixel_color(float x,float y,float t){
  float result = ease(map(sin(TWO_PI*(t+scalar_field_offset(x,y))),-1,1,0,1),3.0);
  return 255*result;
}

void draw(){
  background(0);
  
  float t = 1.0*(frameCount-1)%numFrames/numFrames;
  
  // Draws every pixel
  for(int i=margin;i<width-margin;i++){
    for(int j=margin;j<height-margin;j++){
      stroke(pixel_color(i,j,t));
      point(i,j);
    }
  }
  
  // Draws a white rectangle
  stroke(255);
  noFill();
  rect(margin,margin,width-2*margin,height-2*margin);
  
  // Saves the frame
  println(frameCount,"/",numFrames);
  saveFrame("frame###.png");
  
  // Stops when all the frames are rendered
  if(frameCount == numFrames){
    println("finished");
    stop();
  }
}

I hope this was helpful and that you will be creative and come up with better stuff than me !

Bonus : if you know glsl, it would be a better idea to code this in glsl to have much faster rendering.

Advertisements

One thought on “Animated stripes gifs from scalar fields

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s