Baking the arrays on screen with Processing

╄→гoц情女王★ 提交于 2021-02-08 10:27:25

问题


I like working with Processing array functions but when I draw things using this function, I realize it's storing every single drawn shape in the memory, which is causing spikes in CPU. (Especially when it goes up to a few thousands)

How to bake the drawing then remove the array objects on mouserelease? I mean, can Processing behave those objects as a single image after every stroke then I'd clear the array using .remove(0) function?

Here's my code:

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);
  }
}

回答1:


If you want to store the objects into the ArrayList only while the mouse is pressed (drawing new objects) and just have all the old objects to be static on the background out of the ArrayList you can do something like this:

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);
  }
}

The function loadPixels() stores into the pixels[] array all the pixels of the screen, while updatePixels() draws the pixels in pixels[] on the canvas. This way you can just empty your ArrayList every time the mouse is released and, even though when the ArrayList gets some thousands of elements you still get some CPU spikes, when the mouse is not being dragged or the ArrayList has less than a couple thousands of elements it is less CPU consuming.




回答2:


If you don't need to access the drawings objects later (say to change properties), you can simply cache the rendering onto a separate 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();
}

Otherwise you can make use of 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;
}

As mentioned in my comment check out Processing > Examples > Demos > Performance > StaticParticlesRetained

If you need later access to each added circle/drawing you can iterate over the parent 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");
  }

Should you need extra functionality (like a separate property to animate), you can always extend PShape: re-use what's already there add what you need on top:

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);
  } 

}

For the full list of functionalities see PShape javadocs

Starting with the simplest thing though. If you want to simply render many shapes without changing them later PGraphics will do the trick



来源:https://stackoverflow.com/questions/61897824/baking-the-arrays-on-screen-with-processing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!