New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Processing 2.x/3.0 on Mac (10.10.2); framerate in P3D halved vs. Processing 1.5 #3210

Closed
rapatski opened this Issue Apr 24, 2015 · 8 comments

Comments

Projects
None yet
3 participants
@rapatski

rapatski commented Apr 24, 2015

Running the same sketch (line / vertex based) at different OSes using P3D gives various results:

Processing 1.5, OSX 10.10.2: 60 fps (using OPENGL renderer)
Processing 3.0a5, OSX 10.10.2: 25 fps
Processing 3.0a5, Win8 64bit: 55 fps

@benfry

This comment has been minimized.

Show comment
Hide comment
@benfry

benfry Apr 24, 2015

Member

We can't do anything with that information unless you post a sketch for us.

Member

benfry commented Apr 24, 2015

We can't do anything with that information unless you post a sketch for us.

@rapatski

This comment has been minimized.

Show comment
Hide comment
@rapatski

rapatski Apr 24, 2015

Sorry Ben, cleaning it up and will do in a minute

rapatski commented Apr 24, 2015

Sorry Ben, cleaning it up and will do in a minute

@rapatski

This comment has been minimized.

Show comment
Hide comment
@rapatski

rapatski commented Apr 27, 2015

Hmm, sorry, here: http://we.tl/FJblyy8SYi

@benfry

This comment has been minimized.

Show comment
Hide comment
@benfry

benfry Apr 27, 2015

Member

Hm, I'm seeing 60 fps on my machine with 3.0a7 and it doesn't seem maxed out, though at the moment I'm on a fast machine.

@codeanticode Any thoughts here? We should be much speedier with a7. And separately, setting frameRate() higher is giving me System.err messages saying that it's disabling vsync, but from the looks of it, it's not disabling since it's pegged at 60fps.

import processing.opengl.*;

/*
  Test sketch (based on Shiffman's particle examples) exploring framerate in Processing 3.0a5
  Hit any key to display the test pattern with a fixed number of particles.
*/

PGraphicsOpenGL pgl;
GL gl;

//PeasyCam cam;

ArrayList<Pica> picas;
ArrayList<PVector> trail;


int   maxtrail   = 2000;
int   segmentlength = 3;

int    advance    = 3; 
float  strweight  = 2; 

// opacity -- particles have different opacities at different speeds
float slowopacity = 50; 
float fastopacity = 90; 
float factor = 1;

int currentcolourid = 0;

// colour id, primary/secondary, rgb
float[][][] colours = {
  { { 255, 255, 255 }, { 0, 100, 255 } },
  { { 50, 255, 150 }, { 40, 130, 250 } },
  { { 255, 0, 0 }, { 255, 0, 100 } },
  { { 160, 255, 0 }, { 255, 100, 0 } }
}; 


void setup() {

  size(1280, 700, P3D);
  //size(screen.width, screen.height, OPENGL);
  //cam = new PeasyCam(this, 900);
  //hint(DISABLE_OPENGL_2X_SMOOTH);
  //hint(ENABLE_OPENGL_4X_SMOOTH);

  picas = new ArrayList<Pica>();
  trail = new ArrayList<PVector>();

  initTestPattern();

  mouseX = width/2;
  mouseY = height/2;
}

void draw() {

  // UPDATE

  updateTrail();
  updateTargets();

  // handle trail
  handleMouseTrail();

  if (trail.size() != picas.size())
    setTargets();

  // change particle behaviour once in a wjile
  if (random(1) > .99) advance = (random(1) > .5) ? advance - 1 : advance + 1;


  // DRAW

  background(20);

  translate(width/2, height/2);

  blendMode(ADD);

  strokeWeight(strweight);
  noFill();

  // draw trail
  stroke(255, 10);
  beginShape();
  for (int j = 0; j < trail.size(); j++) {
    vertex(trail.get(j).x, trail.get(j).y, trail.get(j).z);
  }
  endShape();

  // draw particles
  for (int j = 0; j < picas.size(); j++) {
    picas.get(j).update();
    picas.get(j).draw(colours[currentcolourid][0], colours[currentcolourid][1], slowopacity*factor, fastopacity*factor);
  }

  // fps
  text(frameRate, 0, 0);

}

void keyReleased()
{
  trail.clear();
  initTestPattern(); 
}

void initTestPattern() {

  float r = min(width, height)/3*2;

  // test pattern to compare frame rates
  for (int i = 0; i < maxtrail; i++) {
    float a = i/float(maxtrail-1)*TWO_PI;
    float x = r*cos(a);//*sin(a*3);
    float y = r*sin(a);//*cos(a);

    PVector p = new PVector(x, y);
    trail.add(p);
  }

}

void handleMouseTrail() {

  if (mousePressed) {
    if (trail.size() < maxtrail) {

      PVector mouse = new PVector(mouseX - width/2, mouseY - height/2);
      PVector last  = (trail.size() > 0) ? trail.get(trail.size()-1) : mouse.get();
      int numsegs = (trail.size() > 0) ? floor(PVector.dist(mouse, last)/segmentlength) : 1;

      for (int i = 0; i < numsegs; i++) {
        PVector p = PVector.add(last, PVector.mult(PVector.div(PVector.sub(mouse, last), float(numsegs)), i));
        trail.add(p);
      }
    } 
    else {
      trail.clear();
    }
  }

}

void setTargets() {

  // append or shorten the pica array depending on the number of 'groups'
  if (picas.size() < trail.size()) {
    for (int i = picas.size(); i < trail.size(); i++) {
      float maxspeed = i%20; //(i%40)/2.0; // note: hardcoded values!
      float maxforce = 0.5 + (i%10)/20.0; //random(0.59, 0.6); // note: hardcoded values!

      Pica b = new Pica(i, mouseX - width/2, mouseY - height/2, 0, maxspeed, maxforce, 16);
      b.target = trail.get(i).get();
      picas.add(b);
    }
  } 
  else
    if (picas.size() > trail.size())
    {
      for (int i = picas.size()-1; i > trail.size()-1; i--) {
        picas.remove(i);
      }
    }
}


void updateTrail()
{

  for (int j = 0; j < trail.size(); j++) {
    trail.set(j, arbitraryAxisRotation(trail.get(j), new PVector(0, 1, 0), 0.003));
  }

}

void updateTargets() {
  // set targets
  for (int j = 0; j < picas.size(); j++) {
    picas.get(j).target_index = (picas.get(j).target_index + advance)%trail.size();
    if (picas.get(j).target_index < 0) picas.get(j).target_index += trail.size();

    //PVector target = new PVector(text_points[j][picas[j][i].target_index].x, text_points[j][picas[j][i].target_index].y, 0);
    picas.get(j).target = trail.get(picas.get(j).target_index);
  }
}


// functions

color mapColor(float value, float minvalue, float maxvalue, float[] mincolor, float[] maxcolor) {

  float r, g, b;
  float dr, dg, db;

  float time = (value - minvalue) / (maxvalue - minvalue);

  dr = maxcolor[0] - mincolor[0];
  dg = maxcolor[1] - mincolor[1];
  db = maxcolor[2] - mincolor[2];

  r = mincolor[0] + time*dr;
  g = mincolor[1] + time*dg;
  b = mincolor[2] + time*db;

  color c = color(r, g, b);
  return c;

}

PVector arbitraryAxisRotation(PVector vector, PVector axis, float theta) {
  PVector result = new PVector(0, 0, 0);
  float x = vector.x;
  float y = vector.y;
  float z = vector.z;
  float u = axis.x;
  float v = axis.y;
  float w = axis.z;
  result.x = u*(u*x + v*y + w*z) * (1 - cos(theta)) + x*cos(theta) + (-w*y + v*z) * sin(theta);
  result.y = v*(u*x + v*y + w*z) * (1 - cos(theta)) + y*cos(theta) + (w*x - u*z) * sin(theta);
  result.z = w*(u*x + v*y + w*z) * (1 - cos(theta)) + z*cos(theta) + (-v*x + u*y) * sin(theta);
  return result;
}

// Arrive
// Credits: Daniel Shiffman <http://www.shiffman.net>

class Pica {

  PVector loc;
  PVector vel;
  PVector acc;

  int index;

  PVector target;
  int target_index;

  float r;

  float maxforce;
  float maxspeed;

  PVector[] history;

  Pica(int index, float x, float y, float z, float maxspeed, float maxforce, int maxtrail) {

    this.index = index;
    this.target_index = index;

    acc = new PVector(0,0);
    vel = new PVector(0,0);
    loc = new PVector(x, y, z);

    r = 3.0;

    this.maxspeed = maxspeed;
    this.maxforce = maxforce;

    history = new PVector[maxtrail];

  }

  // Method to update location
  void update() {

    //update target
    arrive(target);

    // Update velocity
    vel.add(acc);
    // Limit speed
    vel.limit(maxspeed);
    loc.add(vel);
    // Reset accelertion to 0 each cycle
    acc.mult(0);

    for(int i = history.length-1; i > 0; i--) {
      history[i] = history[i-1];
    }
    history[0] = new PVector(loc.x, loc.y, 0);

  }

  void draw(float[] _colour1, float[] _colour2, float _slowopacity, float _fastopacity) {

    noFill();
    //stroke(0);
    beginShape();

    //if(history.length > 0)
    //rect(history[0].x, history[0].y, 5, 5);

    for(int i = 1; i < history.length; i++) {

      if(history[i] != null) {
        float angle = atan((history[i].x - history[i-1].x) / (history[i].y - history[i-1].y)); // ugly, same value can be derived from steer

        color c = mapColor(abs(angle), 0, PI/2.0, _colour1, _colour2); // vloeiende overgangen
        float o = map(vel.mag(), 0, 20, _slowopacity, _fastopacity); // opacity

        stroke(c, o); //255 - i/float(history.length)*255);
        vertex(history[i].x, history[i].y);
      }

    }
    endShape();

  }

  void arrive(PVector target) {
    acc.add(steer(target, true));
  }

  PVector steer(PVector target, boolean slowdown) {

    PVector steer;  
    PVector desired = PVector.sub(target, loc); 
    float d = desired.mag(); 

    if (d > 0) {

      desired.normalize();
      if ((slowdown) && (d < 100.0f)) {
        desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
      }
      else {
        desired.mult(maxspeed);
      }

      steer = PVector.sub(desired, vel);
      steer.limit(maxforce);  // Limit to maximum steering force

    }
    else {
      steer = new PVector(0,0);
    }

    return steer;
  }

}
Member

benfry commented Apr 27, 2015

Hm, I'm seeing 60 fps on my machine with 3.0a7 and it doesn't seem maxed out, though at the moment I'm on a fast machine.

@codeanticode Any thoughts here? We should be much speedier with a7. And separately, setting frameRate() higher is giving me System.err messages saying that it's disabling vsync, but from the looks of it, it's not disabling since it's pegged at 60fps.

import processing.opengl.*;

/*
  Test sketch (based on Shiffman's particle examples) exploring framerate in Processing 3.0a5
  Hit any key to display the test pattern with a fixed number of particles.
*/

PGraphicsOpenGL pgl;
GL gl;

//PeasyCam cam;

ArrayList<Pica> picas;
ArrayList<PVector> trail;


int   maxtrail   = 2000;
int   segmentlength = 3;

int    advance    = 3; 
float  strweight  = 2; 

// opacity -- particles have different opacities at different speeds
float slowopacity = 50; 
float fastopacity = 90; 
float factor = 1;

int currentcolourid = 0;

// colour id, primary/secondary, rgb
float[][][] colours = {
  { { 255, 255, 255 }, { 0, 100, 255 } },
  { { 50, 255, 150 }, { 40, 130, 250 } },
  { { 255, 0, 0 }, { 255, 0, 100 } },
  { { 160, 255, 0 }, { 255, 100, 0 } }
}; 


void setup() {

  size(1280, 700, P3D);
  //size(screen.width, screen.height, OPENGL);
  //cam = new PeasyCam(this, 900);
  //hint(DISABLE_OPENGL_2X_SMOOTH);
  //hint(ENABLE_OPENGL_4X_SMOOTH);

  picas = new ArrayList<Pica>();
  trail = new ArrayList<PVector>();

  initTestPattern();

  mouseX = width/2;
  mouseY = height/2;
}

void draw() {

  // UPDATE

  updateTrail();
  updateTargets();

  // handle trail
  handleMouseTrail();

  if (trail.size() != picas.size())
    setTargets();

  // change particle behaviour once in a wjile
  if (random(1) > .99) advance = (random(1) > .5) ? advance - 1 : advance + 1;


  // DRAW

  background(20);

  translate(width/2, height/2);

  blendMode(ADD);

  strokeWeight(strweight);
  noFill();

  // draw trail
  stroke(255, 10);
  beginShape();
  for (int j = 0; j < trail.size(); j++) {
    vertex(trail.get(j).x, trail.get(j).y, trail.get(j).z);
  }
  endShape();

  // draw particles
  for (int j = 0; j < picas.size(); j++) {
    picas.get(j).update();
    picas.get(j).draw(colours[currentcolourid][0], colours[currentcolourid][1], slowopacity*factor, fastopacity*factor);
  }

  // fps
  text(frameRate, 0, 0);

}

void keyReleased()
{
  trail.clear();
  initTestPattern(); 
}

void initTestPattern() {

  float r = min(width, height)/3*2;

  // test pattern to compare frame rates
  for (int i = 0; i < maxtrail; i++) {
    float a = i/float(maxtrail-1)*TWO_PI;
    float x = r*cos(a);//*sin(a*3);
    float y = r*sin(a);//*cos(a);

    PVector p = new PVector(x, y);
    trail.add(p);
  }

}

void handleMouseTrail() {

  if (mousePressed) {
    if (trail.size() < maxtrail) {

      PVector mouse = new PVector(mouseX - width/2, mouseY - height/2);
      PVector last  = (trail.size() > 0) ? trail.get(trail.size()-1) : mouse.get();
      int numsegs = (trail.size() > 0) ? floor(PVector.dist(mouse, last)/segmentlength) : 1;

      for (int i = 0; i < numsegs; i++) {
        PVector p = PVector.add(last, PVector.mult(PVector.div(PVector.sub(mouse, last), float(numsegs)), i));
        trail.add(p);
      }
    } 
    else {
      trail.clear();
    }
  }

}

void setTargets() {

  // append or shorten the pica array depending on the number of 'groups'
  if (picas.size() < trail.size()) {
    for (int i = picas.size(); i < trail.size(); i++) {
      float maxspeed = i%20; //(i%40)/2.0; // note: hardcoded values!
      float maxforce = 0.5 + (i%10)/20.0; //random(0.59, 0.6); // note: hardcoded values!

      Pica b = new Pica(i, mouseX - width/2, mouseY - height/2, 0, maxspeed, maxforce, 16);
      b.target = trail.get(i).get();
      picas.add(b);
    }
  } 
  else
    if (picas.size() > trail.size())
    {
      for (int i = picas.size()-1; i > trail.size()-1; i--) {
        picas.remove(i);
      }
    }
}


void updateTrail()
{

  for (int j = 0; j < trail.size(); j++) {
    trail.set(j, arbitraryAxisRotation(trail.get(j), new PVector(0, 1, 0), 0.003));
  }

}

void updateTargets() {
  // set targets
  for (int j = 0; j < picas.size(); j++) {
    picas.get(j).target_index = (picas.get(j).target_index + advance)%trail.size();
    if (picas.get(j).target_index < 0) picas.get(j).target_index += trail.size();

    //PVector target = new PVector(text_points[j][picas[j][i].target_index].x, text_points[j][picas[j][i].target_index].y, 0);
    picas.get(j).target = trail.get(picas.get(j).target_index);
  }
}


// functions

color mapColor(float value, float minvalue, float maxvalue, float[] mincolor, float[] maxcolor) {

  float r, g, b;
  float dr, dg, db;

  float time = (value - minvalue) / (maxvalue - minvalue);

  dr = maxcolor[0] - mincolor[0];
  dg = maxcolor[1] - mincolor[1];
  db = maxcolor[2] - mincolor[2];

  r = mincolor[0] + time*dr;
  g = mincolor[1] + time*dg;
  b = mincolor[2] + time*db;

  color c = color(r, g, b);
  return c;

}

PVector arbitraryAxisRotation(PVector vector, PVector axis, float theta) {
  PVector result = new PVector(0, 0, 0);
  float x = vector.x;
  float y = vector.y;
  float z = vector.z;
  float u = axis.x;
  float v = axis.y;
  float w = axis.z;
  result.x = u*(u*x + v*y + w*z) * (1 - cos(theta)) + x*cos(theta) + (-w*y + v*z) * sin(theta);
  result.y = v*(u*x + v*y + w*z) * (1 - cos(theta)) + y*cos(theta) + (w*x - u*z) * sin(theta);
  result.z = w*(u*x + v*y + w*z) * (1 - cos(theta)) + z*cos(theta) + (-v*x + u*y) * sin(theta);
  return result;
}

// Arrive
// Credits: Daniel Shiffman <http://www.shiffman.net>

class Pica {

  PVector loc;
  PVector vel;
  PVector acc;

  int index;

  PVector target;
  int target_index;

  float r;

  float maxforce;
  float maxspeed;

  PVector[] history;

  Pica(int index, float x, float y, float z, float maxspeed, float maxforce, int maxtrail) {

    this.index = index;
    this.target_index = index;

    acc = new PVector(0,0);
    vel = new PVector(0,0);
    loc = new PVector(x, y, z);

    r = 3.0;

    this.maxspeed = maxspeed;
    this.maxforce = maxforce;

    history = new PVector[maxtrail];

  }

  // Method to update location
  void update() {

    //update target
    arrive(target);

    // Update velocity
    vel.add(acc);
    // Limit speed
    vel.limit(maxspeed);
    loc.add(vel);
    // Reset accelertion to 0 each cycle
    acc.mult(0);

    for(int i = history.length-1; i > 0; i--) {
      history[i] = history[i-1];
    }
    history[0] = new PVector(loc.x, loc.y, 0);

  }

  void draw(float[] _colour1, float[] _colour2, float _slowopacity, float _fastopacity) {

    noFill();
    //stroke(0);
    beginShape();

    //if(history.length > 0)
    //rect(history[0].x, history[0].y, 5, 5);

    for(int i = 1; i < history.length; i++) {

      if(history[i] != null) {
        float angle = atan((history[i].x - history[i-1].x) / (history[i].y - history[i-1].y)); // ugly, same value can be derived from steer

        color c = mapColor(abs(angle), 0, PI/2.0, _colour1, _colour2); // vloeiende overgangen
        float o = map(vel.mag(), 0, 20, _slowopacity, _fastopacity); // opacity

        stroke(c, o); //255 - i/float(history.length)*255);
        vertex(history[i].x, history[i].y);
      }

    }
    endShape();

  }

  void arrive(PVector target) {
    acc.add(steer(target, true));
  }

  PVector steer(PVector target, boolean slowdown) {

    PVector steer;  
    PVector desired = PVector.sub(target, loc); 
    float d = desired.mag(); 

    if (d > 0) {

      desired.normalize();
      if ((slowdown) && (d < 100.0f)) {
        desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
      }
      else {
        desired.mult(maxspeed);
      }

      steer = PVector.sub(desired, vel);
      steer.limit(maxforce);  // Limit to maximum steering force

    }
    else {
      steer = new PVector(0,0);
    }

    return steer;
  }

}
@rapatski

This comment has been minimized.

Show comment
Hide comment
@rapatski

rapatski Apr 27, 2015

What happens when you just up the maxtrail particle count until even your fast machine struggles? Like mentioned before, I'm seeing a 30fps difference between 1.5 and 3.0

On 27 Apr 2015, at 13:30, Ben Fry notifications@github.com wrote:

Hm, I'm seeing 60 fps on my machine with 3.0a7 and it doesn't seem maxed out, though at the moment I'm on a fast machine.

@codeanticode Any thoughts here? We should be much speedier with a7. And separately, setting frameRate() higher is giving me System.err messages saying that it's disabling vsync, but from the looks of it, it's not disabling since it's pegged at 60fps.

import processing.opengl.*;

/*
Test sketch (based on Shiffman's particle examples) exploring framerate in Processing 3.0a5
Hit any key to display the test pattern with a fixed number of particles.
*/

PGraphicsOpenGL pgl;
GL gl;

//PeasyCam cam;

ArrayList picas;
ArrayList trail;

int maxtrail = 2000;
int segmentlength = 3;

int advance = 3;
float strweight = 2;

// opacity -- particles have different opacities at different speeds
float slowopacity = 50;
float fastopacity = 90;
float factor = 1;

int currentcolourid = 0;

// colour id, primary/secondary, rgb
float[][][] colours = {
{ { 255, 255, 255 }, { 0, 100, 255 } },
{ { 50, 255, 150 }, { 40, 130, 250 } },
{ { 255, 0, 0 }, { 255, 0, 100 } },
{ { 160, 255, 0 }, { 255, 100, 0 } }
};

void setup() {

size(1280, 700, P3D);
//size(screen.width, screen.height, OPENGL);
//cam = new PeasyCam(this, 900);
//hint(DISABLE_OPENGL_2X_SMOOTH);
//hint(ENABLE_OPENGL_4X_SMOOTH);

picas = new ArrayList();
trail = new ArrayList();

initTestPattern();

mouseX = width/2;
mouseY = height/2;
}

void draw() {

// UPDATE

updateTrail();
updateTargets();

// handle trail
handleMouseTrail();

if (trail.size() != picas.size())
setTargets();

// change particle behaviour once in a wjile
if (random(1) > .99) advance = (random(1) > .5) ? advance - 1 : advance + 1;

// DRAW

background(20);

translate(width/2, height/2);

blendMode(ADD);

strokeWeight(strweight);
noFill();

// draw trail
stroke(255, 10);
beginShape();
for (int j = 0; j < trail.size(); j++) {
vertex(trail.get(j).x, trail.get(j).y, trail.get(j).z);
}
endShape();

// draw particles
for (int j = 0; j < picas.size(); j++) {
picas.get(j).update();
picas.get(j).draw(colours[currentcolourid][0], colours[currentcolourid][1], slowopacity_factor, fastopacity_factor);
}

// fps
text(frameRate, 0, 0);

}

void keyReleased()
{
trail.clear();
initTestPattern();
}

void initTestPattern() {

float r = min(width, height)/3*2;

// test pattern to compare frame rates
for (int i = 0; i < maxtrail; i++) {
float a = i/float(maxtrail-1)_TWO_PI;
float x = r_cos(a);//_sin(a_3);
float y = r_sin(a);//_cos(a);

PVector p = new PVector(x, y);
trail.add(p);

}

}

void handleMouseTrail() {

if (mousePressed) {
if (trail.size() < maxtrail) {

  PVector mouse = new PVector(mouseX - width/2, mouseY - height/2);
  PVector last  = (trail.size() > 0) ? trail.get(trail.size()-1) : mouse.get();
  int numsegs = (trail.size() > 0) ? floor(PVector.dist(mouse, last)/segmentlength) : 1;

  for (int i = 0; i < numsegs; i++) {
    PVector p = PVector.add(last, PVector.mult(PVector.div(PVector.sub(mouse, last), float(numsegs)), i));
    trail.add(p);
  }
} 
else {
  trail.clear();
}

}

}

void setTargets() {

// append or shorten the pica array depending on the number of 'groups'
if (picas.size() < trail.size()) {
for (int i = picas.size(); i < trail.size(); i++) {
float maxspeed = i%20; //(i%40)/2.0; // note: hardcoded values!
float maxforce = 0.5 + (i%10)/20.0; //random(0.59, 0.6); // note: hardcoded values!

  Pica b = new Pica(i, mouseX - width/2, mouseY - height/2, 0, maxspeed, maxforce, 16);
  b.target = trail.get(i).get();
  picas.add(b);
}

}
else
if (picas.size() > trail.size())
{
for (int i = picas.size()-1; i > trail.size()-1; i--) {
picas.remove(i);
}
}
}

void updateTrail()
{

for (int j = 0; j < trail.size(); j++) {
trail.set(j, arbitraryAxisRotation(trail.get(j), new PVector(0, 1, 0), 0.003));
}

}

void updateTargets() {
// set targets
for (int j = 0; j < picas.size(); j++) {
picas.get(j).target_index = (picas.get(j).target_index + advance)%trail.size();
if (picas.get(j).target_index < 0) picas.get(j).target_index += trail.size();

//PVector target = new PVector(text_points[j][picas[j][i].target_index].x, text_points[j][picas[j][i].target_index].y, 0);
picas.get(j).target = trail.get(picas.get(j).target_index);

}
}

// functions

color mapColor(float value, float minvalue, float maxvalue, float[] mincolor, float[] maxcolor) {

float r, g, b;
float dr, dg, db;

float time = (value - minvalue) / (maxvalue - minvalue);

dr = maxcolor[0] - mincolor[0];
dg = maxcolor[1] - mincolor[1];
db = maxcolor[2] - mincolor[2];

r = mincolor[0] + time_dr;
g = mincolor[1] + time_dg;
b = mincolor[2] + time*db;

color c = color(r, g, b);
return c;

}

PVector arbitraryAxisRotation(PVector vector, PVector axis, float theta) {
PVector result = new PVector(0, 0, 0);
float x = vector.x;
float y = vector.y;
float z = vector.z;
float u = axis.x;
float v = axis.y;
float w = axis.z;
result.x = u_(u_x + v_y + w_z) * (1 - cos(theta)) + x_cos(theta) + (-w_y + v_z) * sin(theta);
result.y = v_(u_x + v_y + w_z) * (1 - cos(theta)) + y_cos(theta) + (w_x - u_z) * sin(theta);
result.z = w_(u_x + v_y + w_z) * (1 - cos(theta)) + z_cos(theta) + (-v_x + u*y) * sin(theta);
return result;
}

// Arrive
// Credits: Daniel Shiffman http://www.shiffman.net

class Pica {

PVector loc;
PVector vel;
PVector acc;

int index;

PVector target;
int target_index;

float r;

float maxforce;
float maxspeed;

PVector[] history;

Pica(int index, float x, float y, float z, float maxspeed, float maxforce, int maxtrail) {

this.index = index;
this.target_index = index;

acc = new PVector(0,0);
vel = new PVector(0,0);
loc = new PVector(x, y, z);

r = 3.0;

this.maxspeed = maxspeed;
this.maxforce = maxforce;

history = new PVector[maxtrail];

}

// Method to update location
void update() {

//update target
arrive(target);

// Update velocity
vel.add(acc);
// Limit speed
vel.limit(maxspeed);
loc.add(vel);
// Reset accelertion to 0 each cycle
acc.mult(0);

for(int i = history.length-1; i > 0; i--) {
  history[i] = history[i-1];
}
history[0] = new PVector(loc.x, loc.y, 0);

}

void draw(float[] _colour1, float[] _colour2, float _slowopacity, float _fastopacity) {

noFill();
//stroke(0);
beginShape();

//if(history.length > 0)
//rect(history[0].x, history[0].y, 5, 5);

for(int i = 1; i < history.length; i++) {

  if(history[i] != null) {
    float angle = atan((history[i].x - history[i-1].x) / (history[i].y - history[i-1].y)); // ugly, same value can be derived from steer

    color c = mapColor(abs(angle), 0, PI/2.0, _colour1, _colour2); // vloeiende overgangen
    float o = map(vel.mag(), 0, 20, _slowopacity, _fastopacity); // opacity

    stroke(c, o); //255 - i/float(history.length)*255);
    vertex(history[i].x, history[i].y);
  }

}
endShape();

}

void arrive(PVector target) {
acc.add(steer(target, true));
}

PVector steer(PVector target, boolean slowdown) {

PVector steer;  
PVector desired = PVector.sub(target, loc); 
float d = desired.mag(); 

if (d > 0) {

  desired.normalize();
  if ((slowdown) && (d < 100.0f)) {
    desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
  }
  else {
    desired.mult(maxspeed);
  }

  steer = PVector.sub(desired, vel);
  steer.limit(maxforce);  // Limit to maximum steering force

}
else {
  steer = new PVector(0,0);
}

return steer;

}

}

Reply to this email directly or view it on GitHub.

rapatski commented Apr 27, 2015

What happens when you just up the maxtrail particle count until even your fast machine struggles? Like mentioned before, I'm seeing a 30fps difference between 1.5 and 3.0

On 27 Apr 2015, at 13:30, Ben Fry notifications@github.com wrote:

Hm, I'm seeing 60 fps on my machine with 3.0a7 and it doesn't seem maxed out, though at the moment I'm on a fast machine.

@codeanticode Any thoughts here? We should be much speedier with a7. And separately, setting frameRate() higher is giving me System.err messages saying that it's disabling vsync, but from the looks of it, it's not disabling since it's pegged at 60fps.

import processing.opengl.*;

/*
Test sketch (based on Shiffman's particle examples) exploring framerate in Processing 3.0a5
Hit any key to display the test pattern with a fixed number of particles.
*/

PGraphicsOpenGL pgl;
GL gl;

//PeasyCam cam;

ArrayList picas;
ArrayList trail;

int maxtrail = 2000;
int segmentlength = 3;

int advance = 3;
float strweight = 2;

// opacity -- particles have different opacities at different speeds
float slowopacity = 50;
float fastopacity = 90;
float factor = 1;

int currentcolourid = 0;

// colour id, primary/secondary, rgb
float[][][] colours = {
{ { 255, 255, 255 }, { 0, 100, 255 } },
{ { 50, 255, 150 }, { 40, 130, 250 } },
{ { 255, 0, 0 }, { 255, 0, 100 } },
{ { 160, 255, 0 }, { 255, 100, 0 } }
};

void setup() {

size(1280, 700, P3D);
//size(screen.width, screen.height, OPENGL);
//cam = new PeasyCam(this, 900);
//hint(DISABLE_OPENGL_2X_SMOOTH);
//hint(ENABLE_OPENGL_4X_SMOOTH);

picas = new ArrayList();
trail = new ArrayList();

initTestPattern();

mouseX = width/2;
mouseY = height/2;
}

void draw() {

// UPDATE

updateTrail();
updateTargets();

// handle trail
handleMouseTrail();

if (trail.size() != picas.size())
setTargets();

// change particle behaviour once in a wjile
if (random(1) > .99) advance = (random(1) > .5) ? advance - 1 : advance + 1;

// DRAW

background(20);

translate(width/2, height/2);

blendMode(ADD);

strokeWeight(strweight);
noFill();

// draw trail
stroke(255, 10);
beginShape();
for (int j = 0; j < trail.size(); j++) {
vertex(trail.get(j).x, trail.get(j).y, trail.get(j).z);
}
endShape();

// draw particles
for (int j = 0; j < picas.size(); j++) {
picas.get(j).update();
picas.get(j).draw(colours[currentcolourid][0], colours[currentcolourid][1], slowopacity_factor, fastopacity_factor);
}

// fps
text(frameRate, 0, 0);

}

void keyReleased()
{
trail.clear();
initTestPattern();
}

void initTestPattern() {

float r = min(width, height)/3*2;

// test pattern to compare frame rates
for (int i = 0; i < maxtrail; i++) {
float a = i/float(maxtrail-1)_TWO_PI;
float x = r_cos(a);//_sin(a_3);
float y = r_sin(a);//_cos(a);

PVector p = new PVector(x, y);
trail.add(p);

}

}

void handleMouseTrail() {

if (mousePressed) {
if (trail.size() < maxtrail) {

  PVector mouse = new PVector(mouseX - width/2, mouseY - height/2);
  PVector last  = (trail.size() > 0) ? trail.get(trail.size()-1) : mouse.get();
  int numsegs = (trail.size() > 0) ? floor(PVector.dist(mouse, last)/segmentlength) : 1;

  for (int i = 0; i < numsegs; i++) {
    PVector p = PVector.add(last, PVector.mult(PVector.div(PVector.sub(mouse, last), float(numsegs)), i));
    trail.add(p);
  }
} 
else {
  trail.clear();
}

}

}

void setTargets() {

// append or shorten the pica array depending on the number of 'groups'
if (picas.size() < trail.size()) {
for (int i = picas.size(); i < trail.size(); i++) {
float maxspeed = i%20; //(i%40)/2.0; // note: hardcoded values!
float maxforce = 0.5 + (i%10)/20.0; //random(0.59, 0.6); // note: hardcoded values!

  Pica b = new Pica(i, mouseX - width/2, mouseY - height/2, 0, maxspeed, maxforce, 16);
  b.target = trail.get(i).get();
  picas.add(b);
}

}
else
if (picas.size() > trail.size())
{
for (int i = picas.size()-1; i > trail.size()-1; i--) {
picas.remove(i);
}
}
}

void updateTrail()
{

for (int j = 0; j < trail.size(); j++) {
trail.set(j, arbitraryAxisRotation(trail.get(j), new PVector(0, 1, 0), 0.003));
}

}

void updateTargets() {
// set targets
for (int j = 0; j < picas.size(); j++) {
picas.get(j).target_index = (picas.get(j).target_index + advance)%trail.size();
if (picas.get(j).target_index < 0) picas.get(j).target_index += trail.size();

//PVector target = new PVector(text_points[j][picas[j][i].target_index].x, text_points[j][picas[j][i].target_index].y, 0);
picas.get(j).target = trail.get(picas.get(j).target_index);

}
}

// functions

color mapColor(float value, float minvalue, float maxvalue, float[] mincolor, float[] maxcolor) {

float r, g, b;
float dr, dg, db;

float time = (value - minvalue) / (maxvalue - minvalue);

dr = maxcolor[0] - mincolor[0];
dg = maxcolor[1] - mincolor[1];
db = maxcolor[2] - mincolor[2];

r = mincolor[0] + time_dr;
g = mincolor[1] + time_dg;
b = mincolor[2] + time*db;

color c = color(r, g, b);
return c;

}

PVector arbitraryAxisRotation(PVector vector, PVector axis, float theta) {
PVector result = new PVector(0, 0, 0);
float x = vector.x;
float y = vector.y;
float z = vector.z;
float u = axis.x;
float v = axis.y;
float w = axis.z;
result.x = u_(u_x + v_y + w_z) * (1 - cos(theta)) + x_cos(theta) + (-w_y + v_z) * sin(theta);
result.y = v_(u_x + v_y + w_z) * (1 - cos(theta)) + y_cos(theta) + (w_x - u_z) * sin(theta);
result.z = w_(u_x + v_y + w_z) * (1 - cos(theta)) + z_cos(theta) + (-v_x + u*y) * sin(theta);
return result;
}

// Arrive
// Credits: Daniel Shiffman http://www.shiffman.net

class Pica {

PVector loc;
PVector vel;
PVector acc;

int index;

PVector target;
int target_index;

float r;

float maxforce;
float maxspeed;

PVector[] history;

Pica(int index, float x, float y, float z, float maxspeed, float maxforce, int maxtrail) {

this.index = index;
this.target_index = index;

acc = new PVector(0,0);
vel = new PVector(0,0);
loc = new PVector(x, y, z);

r = 3.0;

this.maxspeed = maxspeed;
this.maxforce = maxforce;

history = new PVector[maxtrail];

}

// Method to update location
void update() {

//update target
arrive(target);

// Update velocity
vel.add(acc);
// Limit speed
vel.limit(maxspeed);
loc.add(vel);
// Reset accelertion to 0 each cycle
acc.mult(0);

for(int i = history.length-1; i > 0; i--) {
  history[i] = history[i-1];
}
history[0] = new PVector(loc.x, loc.y, 0);

}

void draw(float[] _colour1, float[] _colour2, float _slowopacity, float _fastopacity) {

noFill();
//stroke(0);
beginShape();

//if(history.length > 0)
//rect(history[0].x, history[0].y, 5, 5);

for(int i = 1; i < history.length; i++) {

  if(history[i] != null) {
    float angle = atan((history[i].x - history[i-1].x) / (history[i].y - history[i-1].y)); // ugly, same value can be derived from steer

    color c = mapColor(abs(angle), 0, PI/2.0, _colour1, _colour2); // vloeiende overgangen
    float o = map(vel.mag(), 0, 20, _slowopacity, _fastopacity); // opacity

    stroke(c, o); //255 - i/float(history.length)*255);
    vertex(history[i].x, history[i].y);
  }

}
endShape();

}

void arrive(PVector target) {
acc.add(steer(target, true));
}

PVector steer(PVector target, boolean slowdown) {

PVector steer;  
PVector desired = PVector.sub(target, loc); 
float d = desired.mag(); 

if (d > 0) {

  desired.normalize();
  if ((slowdown) && (d < 100.0f)) {
    desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
  }
  else {
    desired.mult(maxspeed);
  }

  steer = PVector.sub(desired, vel);
  steer.limit(maxforce);  // Limit to maximum steering force

}
else {
  steer = new PVector(0,0);
}

return steer;

}

}

Reply to this email directly or view it on GitHub.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode May 15, 2015

Member

@benfry is the code you posted the one @rapatski uploaded earlier (his link does not longer work)?

In any case, that code is working at 60fps on a Macbook air with integrated intel graphics (HD 5000), after 56e67c9.

Member

codeanticode commented May 15, 2015

@benfry is the code you posted the one @rapatski uploaded earlier (his link does not longer work)?

In any case, that code is working at 60fps on a Macbook air with integrated intel graphics (HD 5000), after 56e67c9.

@benfry

This comment has been minimized.

Show comment
Hide comment
@benfry

benfry May 15, 2015

Member

Yeah, I pasted it since links like that usually don't work by the time we can do anything about them.

I'll close this as fixed for 3.0a8.

Member

benfry commented May 15, 2015

Yeah, I pasted it since links like that usually don't work by the time we can do anything about them.

I'll close this as fixed for 3.0a8.

@benfry benfry closed this May 15, 2015

@rapatski

This comment has been minimized.

Show comment
Hide comment
@rapatski

rapatski May 15, 2015

rapatski commented May 15, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment