So, I ported a Java Processing sketch to p5.js. The sketches should be simple to run - just basic image rasterization. I tried my best to optimize the JS code but have been unsuccessful at getting any decent performance out of it (max framerate reached is under 10). In comparison, the Java code runs flawlessly even though it is unoptimized. Can someone tell me why?
EDIT: Could someone confirm that the JS code does lag for them too?
p5.js
// OPTIMISATIONS
p5.disableFriendlyErrors = true;
// SETUP VARIABLES
var CANVAS_SIZE = 900;
var MAX_FRAME_RATE = 60;
var paused = false;
// GLOBAL VARIABLES
var TEXT_SIZE = 20;
var tiles = 80;
var PD;
var origin_x;
var origin_y;
var img;
var swansea;
const scale = (value, x1, y1, x2, y2) => (value - x1) * (y2 - x2) / (y1 - x1) + x2;
function preload() {
/*
The image will only load if a server
is hosted, else you'll get a
'Cross-Origin Request Blocked' error.
Simplest way to solve this is to use
the Live Server plugin for VSCode.
*/
img = loadImage('data/backgroundless.png');
img.loadPixels();
swansea = loadFont('data/Swansea-q3pd.ttf');
}
function setup() {
createCanvas(CANVAS_SIZE, CANVAS_SIZE, WEBGL);
frameRate(MAX_FRAME_RATE);
smooth();
PD = pixelDensity();
origin_x = -width/2;
origin_y = -height/2;
img.resize(CANVAS_SIZE, CANVAS_SIZE);
textFont(swansea);
textSize(TEXT_SIZE);
}
function draw() {
/*
Using WEBGL moves the origin from the
top left of the Canvas to its center
so we must translate every drawing to
the top left, i.e. (-width/2, -height/2).
*/
translate(origin_x, origin_y);
background('#f1f1f1');
var tile_size = width/tiles;
push();
translate(-origin_x, -origin_y);
rotateY(radians(frameCount));
push();
noStroke();
for (let i=0; i<tiles; i++) {
for (let j=0; j<tiles; j++) {
let x = Math.floor(i * tile_size);
let y = Math.floor(j * tile_size);
let idx = (x + y * width) * PD * 4;
let c = color(
img.pixels[idx],
img.pixels[idx+1],
img.pixels[idx+2],
img.pixels[idx+3]
);
if (img.pixels[idx]==0 && img.pixels[idx+1]==0 && img.pixels[idx+2]==0) {
continue;
}
let b = 1-brightness(c)/255;
let z = scale(b, 0, 1, -100, 100);
push();
translate(origin_x+x, origin_y+y, z);
fill(c);
sphere(tile_size*b*0.8, 3, 3);
pop();
}
}
pop();
pop();
// Print framerate on the screen.
let fps = frameRate();
fill(0);
stroke(0);
text("FPS: " + fps.toFixed(2), 0, TEXT_SIZE);
}
function mousePressed() {
// Pauses the draw() function to reduce
// computation overhead when not needed.
paused ? loop() : noLoop();
paused = !paused;
}
Processing Java
PImage img;
void setup() {
size(900, 900, P3D);
img = loadImage("data/backgroundless.png");
img.resize(900, 900);
}
void draw() {
background(#f1f1f1);
noStroke();
sphereDetail(3);
float tiles = 100;
float tileSize = width/tiles;
push();
translate(width/2,height/2);
rotateY(radians(frameCount));
for (int x = 0; x < tiles; x++) {
for (int y = 0; y < tiles; y++) {
color c = img.get(int(x*tileSize),int(y*tileSize));
float b = map(brightness(c),0,255,1,0);
float z = map(b,0,1,-150,150);
if (red(c)==0 && green(c)==0 && blue(c)==0) {
continue;
}
push();
translate(x*tileSize - width/2, y*tileSize - height/2, z);
fill(c);
sphere(tileSize*b*0.8);
pop();
}
}
pop();
}
You may use this image as the file backgroundless.png;