PROCESSING: How can I draw only every x frames?

2019-01-20 17:13发布

问题:

I'm experimenting with the following Code:

//3D Spectrogram with Microphone Input
//Modified by kylejanzen 2011 - https://kylejanzen.wordpress.com
//Based on script wwritten by John Locke 2011 - http://gracefulspoon.com

//Output .DXF file at any time by pressing "r" on the keyboard

import processing.dxf.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
import peasy.*;

PeasyCam cam;

FFT fftLin;
FFT fftLog;

Waveform audio3D;

Minim minim;
AudioInput microphone;

boolean record;

PFont font;

float camzoom;
float maxX = 0;float maxY = 0;float maxZ = 0;
float minX = 0;float minY = 0;float minZ = 0;

void setup()
{
  size(1250,750,P3D); //screen proportions
  noStroke();
  minim = new Minim(this);
  microphone = minim.getLineIn(Minim.STEREO, 4096); //repeat the song

  cam = new PeasyCam(this, 0, 0, 0, 50);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(500);

  background(255);

  fftLog = new FFT(microphone.bufferSize(),microphone.sampleRate());
  fftLog.logAverages(1,2);  //adjust numbers to adjust spacing;
  float w = float (width/fftLog.avgSize());
  print(fftLog.avgSize());
  float x = w;
  float y = 0;
  float z = 10;
  float radius = 100;
  audio3D = new Waveform(x,y,z,radius);
}
void draw()

{
  background(0);
  // ambientLight(102,102,102);

  if (frameCount>0)
  {
    for(int i = 0; i < fftLog.avgSize(); i++){
      float zoom = 1;
      float jitter = (fftLog.getAvg(i)*2);
      //println(jitter);
      PVector foc = new PVector(audio3D.x+jitter, audio3D.y+jitter, 0);
      PVector cam = new PVector(zoom, zoom, -zoom);
      // camera(foc.x+cam.x+50,foc.y+cam.y+50,foc.z+cam.z+100,foc.x+30,foc.y+30,foc.z+100,0,0,1);
    }
  }
  //play the song
  fftLog.forward(microphone.mix);

  audio3D.update();
  // audio3D.textdraw();

  if(record)
  {
    beginRaw(DXF, "output.dxf");
  }
  audio3D.plotTrace();

  if(record)
  {
    endRaw();
    record = false;
    println("It's Done Bitches! Find your DXF!");
  }
}
void stop()
{
  // always close Minim audio classes when you finish with them
  microphone.close();
  // always stop Minim before exiting
  minim.stop();
  super.stop();
}
class Waveform
{
  float x,y,z;
  float radius;

  PVector[] pts = new PVector[fftLog.avgSize()];

  PVector[] trace = new PVector[0];

  Waveform(float incomingX, float incomingY, float incomingZ, float incomingRadius)
  {
    x = incomingX;
    y = incomingY;
    z = incomingZ;
    radius = incomingRadius;
  }
  void update()
  {
    plot();
  }
  void plot()
  {
    for(int i = 1; i < fftLog.avgSize(); i++)
    {
      int w = int(width/fftLog.avgSize());

      x = i*w;
      y = frameCount*5; // CHANGE THE SPEED
      z = height/4-fftLog.getAvg(i)*4; //change multiplier to reduces height default '10'

      stroke(0);
      point(x, y, z);
      pts[i] = new PVector(x, y, z);
      //increase size of array trace by length+1
      trace = (PVector[]) expand(trace, trace.length+1);
      //always get the next to last
      trace[trace.length-1] = new PVector(pts[i].x, pts[i].y, pts[i].z);
    }
  }
  /* void textdraw()
  {
    for(int i =0; i<fftLog.avgSize(); i++){
      pushMatrix();
      translate(pts[i].x, pts[i].y, pts[i].z);
      rotateY(PI/2);
      rotateZ(PI/2);

      fill(255,255);
      text(round(fftLog.getAvg(i)*100),0,0,0);
      popMatrix();
    }
  } */
  void plotTrace()
  {
    stroke(255,100);
    int inc = fftLog.avgSize();

    for(int i=1; i<trace.length-inc; i++)
    {
      if(i%inc != 0)
      {
        beginShape(POINTS);
        strokeWeight(2);
        fill(0, 0, 0, 100);
        vertex(trace[i].x, trace[i].y, trace[i].z);
        vertex(trace[i-1].x, trace[i-1].y, trace[i-1].z);
        vertex(trace[i+inc].x, trace[i+inc].y, trace[i+inc].z);
        vertex(trace[i-1+inc].x, trace[i-1+inc].y, trace[i-1+inc].z);
        endShape(CLOSE);
      }
    }
  }
}
void keyPressed()
{
  if (key == 'r') record = true;
}

What I currently try to achieve is to reduce the count of generated points on the (moving) (y-)axis. Currently it seems that every frame, a point is generated. My question therefore is fairly simple: How can I let it draw only e.g. every 5 frames? I just can't find the value, which manages that.

Thank you a lot.

回答1:

You've got three options:

Option 1: Call the frameRate() function to reduce the number of frames that get drawn per second.

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

void draw(){
  background(0);
  ellipse(mouseX, mouseY, 20, 20);
}

Option 2: Use the frameCount variable and the modulus % operator to determine when X frames have elapsed.

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

void draw(){
  if(frameCount % 5 == 0){
    background(0);
    ellipse(mouseX, mouseY, 20, 20);
  }
}

Option 3: You could create your own variable that stores the number of frames that have elapsed.

int framesElapsed = 0;

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

void draw(){
  framesElapsed++;

  if(framesElapsed == 5){
    background(0);
    ellipse(mouseX, mouseY, 20, 20);
    framesElapsed = 0;
  }
}

Note that for the simple case, this is just doing what the modulus operator in option 2 is doing. In that case, modulus is probably better. But this becomes useful if you want, for example, different things to happen at different times. In that case you'd have multiple variables keeping track of the "lifetime" of whatever you want to track.

But for your example, option 2 is probably the best option.