# P5.js goes to Processing abnormally slow！

Hello everyone! Does anyone have any research on the transition from p5js to processing?

I tried to convert the p5js code to processing successfully but it runs abnormally slowly. I am not sure what went wrong. Can anyone help me?

p5js code！

let kMax;
let circle = [];
let n = 30;
let inter = 1.5;
let step;
let maxNoise = 100;
let noiseProg = (x) => (x);
let W;
let Hx;
let Hy;
let D;
let C=0;
let P=[];
let run = false;
function setup() {
createCanvas(windowWidth, windowHeight);

W=0;
Hx=width/2;
Hy=height/2;
D=Hy/20;

background(10);
kMax = random(0.5, 1.0);
step = 0.05;
let t;
for (let i = n; i > 0; i--) {
let k;
let noisiness;
let alpha = pow(1 - noiseProg(i / n), 3);
let COLS = [];
COLS[0] = color(255, 0, 0, alpha * 255 * 0.55);
COLS[1] = color(0, 255, 0, alpha * 255 * 0.55);
COLS[2] = color(0, 0, 255, alpha * 255 * 0.55);
circle.push(
new WaveCircle(createVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[0], k, 0.8, noisiness, t - i * step),
new WaveCircle(createVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[1], k, 0.8, noisiness, t - i * step + 0.2),
new WaveCircle(createVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[2], k, 0.8, noisiness, t - i * step + 0.4));
}
noFill();
noStroke();

}

function draw() {
blendMode(BLEND);
//background(10);
fill(10,100);
rect(0,0,width,height)

PlanetGrowth();

for (const i of circle) {
i.drawWave();
i.updateWave();

}

if (mouseIsPressed) {
W+=10;
run = true;
for (const i of circle) {
let r = 50;
const d = dist(i.center.x, i.center.y, random(width), random(height));
const v = map(d, 0, i.radius * 1.5, -i.radius / 3, -1);

var xoff = 0;
var x = map(noise(xoff), 0, 1, 0, width);
xoff += 0.01;

i.addVel(createVector(width / 2 - r * sin(x), height / 2 - r * cos(x)), v * 0.4);
i.addVel(createVector(width / 2 + r * sin(x), height / 2 - r * cos(x)), v * 0.4);

}

}
}

class WaveCircle {
constructor(centerPos, vetrNum, radius, waveHeight, col, k, atten, noisiness, t) //waveHeight 波形高度 k弹力系数 atten衰减率
{
this.center = centerPos;
this.waveH = [];
this.vel = [];
this.vNum = vetrNum;
this.k = k;
this.atten = atten;
this.maxWaveH = waveHeight;
this.col = col;

for (let i = 0; i < n; i++) {
this.k = kMax * sqrt(i / n) * 0.6;
this.noisiness = maxNoise * noiseProg(i / n);
}

for (var i = 0; i < this.vNum; i++) {
this.waveH[i] = 0;
this.vel[i] = 0;
}
}

drawWave() {
const vertNum = this.vNum;
const rStep = TAU / (vertNum * 0.5);
const centerPos = this.center;

noStroke();
fill(this.col);
push();
translate(centerPos);
beginShape();

for (let i = 0; i <= vertNum + 2; i++) {
let theta = i * rStep;
//r1 = cos(theta)+1;
//r2 = sin(theta)+1;
//let radius = baseRadius + noise(k * r1,  k * r2, t) * noisiness;
let x = cos(theta - PI * 0.47) * radius;
let y = sin(theta - PI * 0.47) * radius;
curveVertex(x, y);
}
endShape();
pop();
}

updateWave() {
const maxHeight = this.maxWaveH;
const num = this.vNum;
const waveH = this.waveH;
const vel = this.vel;

for (let i = 0; i < num; i++) {
const prev = i == 0 ? num - 1 : i - 1;
const next = i == num - 1 ? 0 : i + 1;
var accel = waveH[prev] - waveH[i] + waveH[next] - waveH[i];
accel *= this.k;
vel[i] = (vel[i] + accel) * this.atten;
vel[i] -= waveH[i] / 65;
}

for (let i = 0; i < num; i++) {
waveH[i] += vel[i];
if (waveH[i] > maxHeight) {
waveH[i] = maxHeight;
}
}
}

{
let angle = atan2(pos.y - this.center.y, pos.x - this.center.x);
angle = angle < 0 ? angle + TAU : angle;
let i = int(map(angle, 0, TAU, 0, this.vel.length));
this.vel[i] += vel;
}
}

function PlanetGrowth() {

stroke(255);
P.length<W&&P.push({x:Hx,y:Hy})
C+=.01
i=0
for(_ of P)with(_){
mag(x-Hx,y-Hy)<100&&(x=random(width),y=0)
n=noise(x/width-C,y/width-i++*.01)*PI*5
line(x,y,
x+=cos(n)*9-(x-Hx)/D,
y+=sin(n)*9-(y-Hy)/D
)
}

}

processing code!

float kMax;

int n = 30;

ArrayList<WaveCircle> circle;
float inter = 1.5;
float step;
int maxNoise = 100;
//let noiseProg = (x) => (x);
//let W;
//let Hx;
//let Hy;
//let D;
//let C=0;
//let P=[];
//let run = false;
void setup() {
size(1920, 1080,P3D);

circle = new ArrayList<WaveCircle>();

//W=0;
//Hx=width/2;
//Hy=height/2;
//D=Hy/20;

background(10);
kMax = random(0.5, 1.0);
step = 0.05;
float t=0;
for (int i = n; i > 0; i--) {
float k=0;
float noisiness=0;
float alpha = pow(1 - noise(i/n), 3);
color COLS[] = new color[3];
COLS[0] = color(255, 0, 0, alpha * 255 * 0.55);
COLS[1] = color(0, 255, 0, alpha * 255 * 0.55);
COLS[2] = color(0, 0, 255, alpha * 255 * 0.55);

circle.add(new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[0], k, 0.8, noisiness, (t - i * step)));

circle.add( new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[1], k, 0.8, noisiness, t - i * step + 0.2));
circle.add( new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[2], k, 0.8, noisiness, t - i * step + 0.4));
}
noFill();
noStroke();
frameRate(60);
}

void draw() {
println(frameRate);
blendMode(BLEND);
//background(10);
fill(10,100);
rect(0,0,width,height);
float t = frameCount / 100;

//PlanetGrowth();

for (int i =0; i<circle.size();i++ ) {

WaveCircle p = circle.get(i);
p.drawWave();
p.updateWave();
if (mousePressed){
//W+=10;
//run = true;

int r = 50;
float d = dist(p.center.x, p.center.y, random(width), random(height));
float v = map(d, 0, p.radius * 1.5, -p.radius / 3, -1);

float xoff = 0;
float x = map(noise(xoff), 0, 1, 0, width);
xoff += 0.01;

p.addVel(new PVector(width / 2 - r * sin(x), height / 2 - r * cos(x)), v * 0.4);
p.addVel(new PVector(width / 2 + r * sin(x), height / 2 - r * cos(x)), v * 0.4);
p.addVel(new PVector(random(width), random(height)), v * 0.05);

}
}

}

class WaveCircle {

PVector center ;
float waveH[] ;
float vel[] ;
int vNum ;
float k;
float waveHeight;
color col;
float atten;
float maxWaveH;
float noisiness_;
WaveCircle(PVector centerPos, int vetrNum_, float radius_, float waveHeight_, color col_, float k_, float atten_, float noisiness_, float t_) //waveHeight 波形高度 k弹力系数 atten衰减率
{

center = centerPos;
// this.waveH = [];

vNum = vetrNum_;
waveH = new float[vNum];
vel = new float[vNum];
k = k_;
atten = atten_;
maxWaveH = waveHeight_;
col = col_;

for (int i = 0; i < n; i++) {
k = kMax * sqrt(i / n) * 0.6;
noisiness_ = maxNoise * noise(i / n);
}

for (int i = 0; i < vNum; i++) {
waveH[i] = 0;
vel[i] = 0;
}
}

void drawWave() {
float vertNum = vNum;
float rStep = TAU / (vertNum * 0.5);
PVector centerPos = center;

noStroke();
fill(col);
push();
translate(centerPos.x,centerPos.y);
beginShape();

for (int i = 0; i <= vertNum + 2; i++) {
float theta = i * rStep;
//r1 = cos(theta)+1;
//r2 = sin(theta)+1;
//let radius = baseRadius + noise(k * r1,  k * r2, t) * noisiness;
float x = cos(theta - PI * 0.47) * radius;
float y = sin(theta - PI * 0.47) * radius;
curveVertex(x, y);
}
endShape();
pop();
}

void updateWave() {
float maxHeight = maxWaveH;
float num = vNum;

for (int i = 0; i < num; i++) {
int prev = int(i == 0 ? num - 1 : i - 1);
int next = int(i == num - 1 ? 0 : i + 1);
float accel = waveH[prev] - waveH[i] + waveH[next] - waveH[i];
accel *= this.k;
vel[i] = (vel[i] + accel) * this.atten;
vel[i] -= waveH[i] / 65;
waveH[i] += vel[i];
if (waveH[i] > maxHeight) {
waveH[i] = maxHeight;
}
}
///
//for (int i = 0; i < num; i++) {

//}
}

{
float angle = atan2(pos.y - this.center.y, pos.x - this.center.x);
angle = angle < 0 ? angle + TAU : angle;
int i = int(map(angle, 0, TAU, 0, vel.length));
vel[i] += vel_;
}
}

//function PlanetGrowth() {

//  stroke(255);
//    P.length<W&&P.push({x:Hx,y:Hy})
//  C+=.01
//  i=0
//  for(_ of P)with(_){
//    mag(x-Hx,y-Hy)<100&&(x=random(width),y=0)
//    n=noise(x/width-C,y/width-i++*.01)*PI*5
//    line(x,y,
//         x+=cos(n)*9-(x-Hx)/D,
//         y+=sin(n)*9-(y-Hy)/D
//        )
//  }

//}

What speeds are you getting on p5.js vs Processing, on what device?

Also: don’t println() on every frame if you want good performance.

2 Likes

I see 10-20 FPS in Processing vs. 30-50 FPS in p5.js (Chromium based browser, Hardware acceleration enabled) on a 2019 MacBook Pro. This is despite eliminating the println, disabling calls to updateWave, and removing all uses of blendMode. I also made the p5.js canvas the same fixed size as the Processing code. I don’t see anything obviously flawed with the Processing code that would make it slow (I also tried making the local vertNum an int to avoid the floating point modulo operator).

For me this just reinforces my opinion that p5.js is superior to native Processing.

The patient says, “Doctor, it hurts when I do this.”
The doctor says, "Then don’t do that!”
― Henny Youngman

Hmm. I’m not seeing the same visual output behavior from the two codes, so this seems it might be more than just a performance question. Some differences at a glance – Processing sketch has a fixed size (as KumuPaul noted) – also, it is P3D for some reason…? There are a lot of duplicate local variables in class methods that could just be this.myclassvar. The matrix is getting pushed and popped inside the class, which isn’t strictly necessary with this design – you could throw away the PVector center from the class and put one translate statement in draw – but matrix stack changes are only happening 6 times per frame, not 6000, so really not a big deal… and KumuPaul says it isn’t differences in blendMode… my next guess would be something inside drawWave or addVel, although I haven’t looked closely. First goal would be to have the sketches actually producing similar output, then see if there are optimization steps to take.

1 Like

Thank you very much for your reply. There are some differences in the two codes. I re-updated the processing code. Now the function is exactly the same as processing. In p5js, the framerate can reach 60+fps but in processing it is only 10+fps. After trying to comment out println, there is no change or it is still very slow.

float kMax;

int n = 30;

ArrayList<WaveCircle> circle;
float inter = 1.5;
float step;
int maxNoise = 100;
//let noiseProg = (x) => (x);
//let W;
//let Hx;
//let Hy;
float D;
float C=0;
FloatList  Hx = new FloatList();
FloatList  Hy = new FloatList() ;
//let P=[];
//let run = false;
void setup() {
size(1000, 1000,P2D);

D=height/40;
circle = new ArrayList<WaveCircle>();

//W=0;
//Hx=width/2;
//Hy=height/2;
//D=Hy/20;

background(10);

kMax = random(0.5, 1.0);
step = 0.05;
float t=0;
for (int i = n; i > 0; i--) {
float k=0.1;
float noisiness=0;
float alpha = pow(1 - noise(i/n), 3);
color COLS[] = new color[3];
COLS[0] = color(255, 0, 0, alpha * 255 * 0.55);
COLS[1] = color(0, 255, 0, alpha * 255 * 0.55);
COLS[2] = color(0, 0, 255, alpha * 255 * 0.55);

circle.add(new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[0], k, 0.8, noisiness, (t - i * step)));

circle.add( new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[1], k, 0.8, noisiness, t - i * step + 0.2));
circle.add( new WaveCircle(new PVector(width / 2, height / 2), 50, width * 0.1 + i * inter, width * 0.3,
COLS[2], k, 0.8, noisiness, t - i * step + 0.4));
}
noFill();
noStroke();
frameRate(60);
}

void draw() {
println(frameRate);
blendMode(BLEND);
background(10);
PlanetGrowth();
fill(10,100);
rect(0,0,width,height);
float t = frameCount / 100;

//PlanetGrowth();

for (int i =0; i<circle.size();i++ ) {

WaveCircle p = circle.get(i);
p.drawWave();
p.updateWave();
if (mousePressed){
//W+=10;
//run = true;

int r = 50;
float d = dist(p.center.x, p.center.y, random(width), random(height));
float v = map(d, 0, p.radius * 1.5, -p.radius / 3, -1);

float xoff = 0;
float x = map(noise(xoff), 0, 1, 0, width);
xoff += 0.01;

p.addVel(new PVector(width / 2 - r * sin(x), height / 2 - r * cos(x)), v * 0.4);
p.addVel(new PVector(width / 2 + r * sin(x), height / 2 - r * cos(x)), v * 0.4);
p.addVel(new PVector(random(width), random(height)), v * 0.05);

}
}

}

class WaveCircle {

PVector center ;
float waveH[] ;
float vel[] ;
int vNum ;
float k;
float waveHeight;
color col;
float atten;
float maxWaveH;
float noisiness_;
WaveCircle(PVector centerPos, int vetrNum_, float radius_, float waveHeight_, color col_, float k_, float atten_, float noisiness, float t_) //waveHeight 波形高度 k弹力系数 atten衰减率
{

center = centerPos;
// this.waveH = [];

vNum = vetrNum_;
waveH = new float[vNum];
vel = new float[vNum];
k = k_;
atten = atten_;
maxWaveH = waveHeight_;
col = col_;

//for (int i = 0; i < n; i++) {
//  k = kMax * sqrt(i / n) * 0.6;
//  noisiness_ = maxNoise * noise(i / n);
//}

for (int i = 0; i < vNum; i++) {
waveH[i] = 0;
vel[i] = 0;
}
}

void drawWave() {
float vertNum = vNum;
float rStep = TAU / (vertNum * 0.5);
PVector centerPos = center;

noStroke();
fill(col);
push();
translate(centerPos.x,centerPos.y);
beginShape();

for (int i = 0; i <= vertNum + 2; i++) {
float theta = i * rStep;
//r1 = cos(theta)+1;
//r2 = sin(theta)+1;
//let radius = baseRadius + noise(k * r1,  k * r2, t) * noisiness;
float x = cos(theta - PI * 0.47) * radius;
float y = sin(theta - PI * 0.47) * radius;
curveVertex(x, y);
}
endShape();
pop();
}

void updateWave() {
float maxHeight = maxWaveH;
float num = vNum;

for (int i = 0; i < num; i++) {
int prev = int(i == 0 ? num - 1 : i - 1);
int next = int(i == num - 1 ? 0 : i + 1);
float accel = waveH[prev] - waveH[i] + waveH[next] - waveH[i];
accel *= k;
vel[i] = (vel[i] + accel) * atten;
vel[i] -= waveH[i] / 65;
waveH[i] += vel[i];
if (waveH[i] > maxHeight) {
waveH[i] = maxHeight;
}
}
///
//for (int i = 0; i < num; i++) {

//}
}

{
float angle = atan2(pos.y - center.y, pos.x - center.x);
angle = angle < 0 ? angle + TAU : angle;
int i = int(map(angle, 0, TAU, 0, vel.length));
vel[i] += vel_;
}
}

void PlanetGrowth() {

stroke(255);
if(mousePressed)
{
Hx.append(random(width));
Hy.append(0);
}
C+=.01;
//int i=0;
println(Hx.size());

for(int i=0;i<Hx.size();i++){
if( mag(Hx.get(i)-width/2,Hy.get(i)-height/2)<100)
{
Hx.set(i,random(width));
Hy.set(i,0);

}
float n1=noise(Hx.get(i)/width-C,Hy.get(i)/width-i*.01)*PI*5;
float xxx=Hx.get(i)+cos(n1)*9-(Hx.get(i)-width/2)/D;
float yyy =Hy.get(i)+sin(n1)*9-(Hy.get(i)-height/2)/D;

line(Hx.get(i),Hy.get(i),xxx,yyy);
Hx.set(i, xxx) ;
Hy.set(i,yyy);
}

}
1 Like

Thanks for your attempt, although I am very unwilling to believe that p5js is more efficient than processing. But now there is indeed nowhere to be wrong.

I also tried to drop the matrix but nothing changed.