Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

p5.js Graphic buffer performance vs 'normal' rendering

I'm working on an app that uses p5.js for it's front end. It's a canvas that covers the whole screen and has a bunch of different components.

The app has grown to have many components that are rendered each frame, which, as you might expect, has a big impact on cpu usage.

I use an object oriented approach. That allows me to calculate all the required properties for rendering an element when they're constructed so a very small number of computations are done during draw(). The performance issues come clearly from the rendering, which sometimes has loops for things like the example above.

I am looking for ways of optimising the rendering. One idea was using graphic buffers for elements that need loops, e.g. grids and graphs (or shapes in p5.js), and for static elements (elements whose color, size, etc. rarely change).

Another option is to use the noLoop() and redraw() methods but that would make the implementation of several animations a nightmare.

Has anyone experienced performance issues (low fps, high cpu usage) using p5.js when there are a lot of elements being rendered?

Could these issues be worked around or the rendering be optimised somehow?

Will creating graphics buffers and rendering them via image() be faster than rendering normally? for example:

var canvas;
var buffer;
var w = 200,
    h = 200;

var nX = 100,
    nY = 100;

function setup() {
  canvas = createCanvas(400, 400);
  canvas.background(0);
  buffer = makeGridBuffer(w, h, nX, nY);
}

function draw() {
  image(buffer, 0, 0);          // <- Will this be faster than
  makeGrid(w, h, w, h, nX, nY); // <- this?
}

function makeGridBuffer(w, h, nLinesX, nLinesY) {
  var pd = pixelDensity();
  var b = createGraphics(w, h, w/2, h/2);
  var v = null;

  b.background(255);
  b.stroke(255, 0, 0);

  // Make vertical lines
  for (var i = 0; i < nLinesX; i++) {
    v = map(i, 0, nLinesX, 0, w);
    b.line(v, 0, v, h);
  }

  // Make horizontal lines
  for (i = 0; i < nLinesY; i++) {
    v = map(i, 0, nLinesY, 0, w);
    b.line(0, v, w, v);
  }

  return b;
}

function makeGrid(x, y, w, h, nLinesX, nLinesY) {
  push();
  translate(x, y);
  fill(0, 255, 0);
  stroke(0);
  rect(0, 0, w, h);
  var v = null;
  // Make vertical lines
  for (var i = 0; i < nLinesX; i++) {
    v = map(i, 0, nLinesX, 0, w);
    line(v, 0, v, h);
  }

  // Make horizontal lines
  for (i = 0; i < nLinesY; i++) {
    v = map(i, 0, nLinesY, 0, w);
    line(0, v, w, v);
  }

  pop();
}

Pen here

Thank you all in advance!

like image 263
aapa320 Avatar asked Oct 17 '22 20:10

aapa320


1 Answers

Will creating graphics buffers and rendering them via image() be faster than rendering normally?

What happened when you tried? You went through all of that trouble creating an example, so why don't you just run it and see what happens?

For example, if I crank nX and nY up to 10000 each, and then comment out the image(buffer, 0, 0) line, so that the program is manually creating the scene every frame, then I get an FPS of around 10. This shows the problem of the manual drawing slowing down the FPS.

But if I then comment out the makeGrid(w, h, w, h, nX, nY) line so that only the image(buffer, 0, 0) is being run, then I get an FPS of 60. This shows that creating the buffer ahead of time is better for your FPS.

Your example program draws two different things based on which line is run, but hopefully it makes intuitive sense: if you have a very complex scene, then it's better to pre-render it.

Here is a simple example that shows the difference in speed between drawing a bunch of stuff each frame vs using a buffer:

var buffer;
var circles = 10000;

function setup() {
   createCanvas(400, 400);
   buffer = createGraphics(width, height);
   makeCircleBuffer();
}

function draw() {
    if(mouseIsPressed){
        image(buffer, 0, 0);
    }
    else{
        drawCircles();  
    }

    textSize(36);
    text(frameRate(), 50, height/2);

}

function drawCircles(){
    randomSeed(0);
    for(var i = 0; i < circles; i++){
        ellipse(random(width), random(height), 20, 20); 
    }
}

function makeCircleBuffer() {
    randomSeed(1);
    for(var i = 0; i < circles; i++){
        buffer.ellipse(random(width), random(height), 20, 20);  
    }
}

Press the mouse to switch to a buffer approach, and notice how much faster it is.

That's going to be true no matter what animation framework you use. Switching to another framework isn't going to magically fix your problems.

like image 140
Kevin Workman Avatar answered Oct 20 '22 01:10

Kevin Workman