使用 Processing 在屏幕上烘焙阵列

Baking the arrays on screen with Processing

我喜欢使用 Processing 数组函数,但是当我使用这个函数绘制东西时,我意识到它会将每个绘制的形状存储在内存中,这会导致 CPU 出现峰值。 (尤其是涨到几千的时候)

如何烘焙图形然后删除mouserelease 上的数组对象?我的意思是,Processing 能否在每次笔画后将这些对象视为单个图像,然后我会使用 .remove(0) 函数清除数组?

这是我的代码:

ArrayList <Drawing> drawings = new ArrayList <Drawing>();

void setup() {
  size(400, 400);
  background(255);
  colorMode(HSB);
}

void draw() {
  background(255);
  for (int i=0;i<drawings.size();i++) {
    drawings.get(i).display();


  }

  println(drawings.size());
}

void mouseDragged() {


  drawings.add(new Drawing(mouseX, mouseY));

}



class Drawing {
  float x, y, r;
  color c;

  Drawing(float ax, float ay) {
    x=ax;
    y=ay;
    r=random(2, 20);
    c=color(random(100, 200), 255, 255, 88);
  }

  void display() {
    noStroke();
    fill(c, 100);
    ellipse(x,y, r, r);
  }
}

如果你只想在按下鼠标(绘制新对象)时将对象存储到 ArrayList 中,并且只是让所有旧对象在 ArrayList 的背景上保持静态,你可以这样做:

ArrayList<Drawing> drawings = new ArrayList();
boolean flag = false;

void setup()
{
  size(400, 400);
  background(255);
  colorMode(HSB);
  loadPixels();
}

void draw()
{
  updatePixels();
  if(flag)
  {
    for(Drawing drawing : drawings)
    {
      drawing.display();
    }
  }
  println(drawings.size());
}

void mouseDragged()
{
  flag = true;
  Drawing drawing = new Drawing(mouseX, mouseY);
  drawings.add(drawing);
}

void mouseReleased()
{
  flag = false;
  loadPixels();
  drawings = new ArrayList();
}

class Drawing
{
  float x, y, r;
  color c;

  Drawing(float ax, float ay)
  {
    x=ax;
    y=ay;
    r=random(2, 20);
    c=color(random(100, 200), 255, 255, 88);
  }

  public void display()
  {
    noStroke();
    fill(c, 100);
    ellipse(x,y, r, r);
  }
}

函数 loadPixels() 将屏幕的所有像素存储到 pixels[] 数组中,而 updatePixels() 在 canvas 上绘制 pixels[] 中的像素。这样你就可以在每次释放鼠标时清空你的 ArrayList,即使当 ArrayList 获得数千个元素时你仍然会得到一些 CPU 尖峰,当鼠标没有被拖动或者 ArrayList 少于它减少了数千个元素 CPU 消耗。

如果以后不需要访问绘图对象(比如更改属性),您可以简单地将渲染缓存到单独的 PGraphics layer:

PGraphics drawings;

void setup() {
  size(400, 400);
  colorMode(HSB);

  drawings = createGraphics(width, height);
  // use drawing commands between beginDraw() / endDraw() calls
  drawings.beginDraw();
  drawings.background(255);
  drawings.colorMode(HSB);
  drawings.noStroke();
  drawings.endDraw();
}

void draw() {
  background(255);
  // PGraphics extends PImage so you can render it the same way
  image(drawings, 0, 0);
  println((int)frameRate); 
}

void mouseDragged() {
  drawRandomCircle(drawings, mouseX, mouseY);
}

void drawRandomCircle(PGraphics layer, float x, float y){
  float diameter = random(2, 20);
  layer.beginDraw();
    layer.fill(color(random(100, 200), 255, 255, 88));
    layer.ellipse(x, y, diameter, diameter);
  layer.endDraw();
}

否则你可以使用PShape:

PShape drawings;

void setup() {
  size(400, 400, P2D);
  smooth();
  background(255);
  colorMode(HSB);
  // create a PShape group to append circles to later
  drawings = createShape(GROUP);
}

void draw() {
  background(255);
  // render PShape
  shape(drawings);

  println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}

void mouseDragged() {

  drawings.addChild(addRandomCircle(mouseX, mouseY));

}

PShape addRandomCircle(float x, float y){
  float diameter = random(2, 20);

  // create an ellipse PShape with the desired dimensions, position, fill and (no)stroke
  PShape circle = createShape(ELLIPSE, x, y, diameter, diameter);
  circle.setFill(color(random(100, 200), 255, 255, 88));
  circle.setStroke(false);

  return circle;
}

正如我评论中提到的,查看 Processing > Examples > Demos > Performance > StaticParticlesRetained

如果您以后需要访问每个添加的 circle/drawing 您可以迭代父 PShape:

// iterate though nested PShapes
  for(int i = 0 ; i < drawings.getChildCount(); i++){
    // access each PShape
    PShape drawing = drawings.getChild(i);
    // access PShape properties
    println("drawings[" + i + "] has " + drawing.getVertexCount() + " vertices");
  }

如果您需要额外的功能(例如单独的 属性 来制作动画),您可以随时 extend PShape:重新使用已有的功能,在顶部添加您需要的功能:

PShape drawings;

void setup() {
  size(400, 400, P2D);
  smooth();
  background(255);
  colorMode(HSB);
  // create a PShape group to append circles to later
  drawings = createShape(GROUP);
}

void draw() {
  background(255);
  // use custom functionality
  for(int i = 0 ; i < drawings.getChildCount(); i++){
    // cast from PShape superclass to the custom Drawing subclass
    Drawing drawing = (Drawing)drawings.getChild(i);
    // use the custom functionality
    drawing.update(i);
  }

  // render PShape
  shape(drawings);
  println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}

void mouseDragged() {

  drawings.addChild(new Drawing((PGraphicsOpenGL)g, mouseX, mouseY));

}

class Drawing extends PShapeOpenGL{

  float x, y, diameter;

  Drawing(PGraphicsOpenGL pg, float x, float y){
    // call PShape super constructor setting this as a primitive (e.g. POINT, LINE, RECT, ELLIPSE, etc.)
    super(pg, PShape.PRIMITIVE);
    setKind(ELLIPSE);

    diameter = random(2, 20);
    // set (ellipse) shape parameters 
    setParams(new float[]{x, y, diameter, diameter});
    // fill  
    setFill(color(random(100, 200), 255, 255, 88));
    // disable stroke
    setStroke(false);

    // remember original position
    this.x = x;
    this.y = y;
  }

  // a custom functionality on top of PShape
  void update(int index){
    float offset = map(sin((frameCount + ((index+1) * 10)) * 0.025), -1.0, 1.0, -15, 15);
    // reset transformations
    this.resetMatrix();
    // translate backwards
    this.translate(-x, -y);
    // translate back + the offset
    this.translate(x + offset, y);
  } 

}

有关功能的完整列表,请参阅 PShape javadocs

虽然从最简单的事情开始。如果你想简单地渲染许多形状而不改变它们,PGraphics 可以解决这个问题