EDIT: I just realized you want this for p5.js which, oddly, doesn’t appear to have an equivalent to PShape for storing geometry. Unless someone has a work-around for p5, you might be better off trying three.js instead.
Original response:
On my 7 year old machine, I can set N as high as 450 and still get 60 fps.
EDIT: skip to below for QUAD-based code.
int N = 64;
PShape s;
void setup() {
size( 800, 800, P3D );
float [][] data = new float[N+1][N+1]; // leave a strip of 0s on the right and bottom
for( int j=0; j<N; j++ )
for( int i=0; i<N; i++ ) {
float x = 2.*i/N-1, y = 2.*j/N-1,
a = atan2( y, x ), r = sqrt(x*x+y*y);
data[j][i] = 1.1+cos(TAU*2*r+3*a) + random(.5);
}
s = createShape();
s.beginShape(TRIANGLES);
s.noStroke();
for( int i=0; i<N; i++ ) {
// -Y side
float z2 = data[0][i];
s.vertex( i+1, 0, 0 );
s.vertex( i, 0, 0 );
s.vertex( i+1, 0, z2 );
s.vertex( i+1, 0, z2 );
s.vertex( i, 0, 0 );
s.vertex( i, 0, z2 );
}
for( int j=0; j<N; j++ ) {
float z0, z1, z2;
// -X side
z1 = data[j][0];
s.vertex( 0, j, 0 );
s.vertex( 0, j+1, 0 );
s.vertex( 0, j, z1 );
s.vertex( 0, j, z1 );
s.vertex( 0, j+1, 0 );
s.vertex( 0, j+1, z1 );
for( int i=0; i<N; i++ ) {
z0 = z1;
z1 = data[j][i+1];
z2 = data[j+1][i];
// +Z top
s.vertex( i, j, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i+1, j, z0 );
s.vertex( i+1, j, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i+1, j+1, z0 );
// +X side
s.vertex( i+1, j, z0 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j, z1 );
s.vertex( i+1, j, z1 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j+1, z1 );
// +Y side
s.vertex( i+1, j+1, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i+1, j+1, z2 );
s.vertex( i+1, j+1, z2 );
s.vertex( i, j+1, z0 );
s.vertex( i, j+1, z2 );
}
}
s.endShape();
}
void draw() {
background( 0, 32, 64 );
camera( 0, 0, N, 0, 0, 0, 0, 1, 0 );
perspective( PI/3, 1, N/4, 2*N );
rotateX( TAU/6. );
lights();
rotateZ( frameCount/115. );
shape( s, -N/2, -N/2 );
fill( 255 );
camera();
perspective();
text( nf( frameRate, 0, 2 ), 10, 20 );
}
EDIT because discourse won’t let me post again:
Not sure why I didn’t use QUADS instead of TRIANGLES. With QUADS I can go up to N=550 with a single grid and the code’s simpler. Here’s a version with multiple grids.
int N = 64;
PShape s1, s2;
PShape genGrid( int N, float [][] data ) {
PShape s = createShape();
s.beginShape(QUADS);
s.noStroke();
for( int i=0; i<N; i++ ) {
// -Y side
float z2 = data[0][i];
s.vertex( i+1, 0, 0 );
s.vertex( i, 0, 0 );
s.vertex( i, 0, z2 );
s.vertex( i+1, 0, z2 );
}
for( int j=0; j<N; j++ ) {
float z0, z1, z2;
// -X side
z1 = data[j][0];
s.vertex( 0, j, 0 );
s.vertex( 0, j+1, 0 );
s.vertex( 0, j+1, z1 );
s.vertex( 0, j, z1 );
for( int i=0; i<N; i++ ) {
z0 = z1;
z1 = data[j][i+1];
z2 = data[j+1][i];
// +Z top
s.vertex( i, j, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j, z0 );
// +X side
s.vertex( i+1, j, z0 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j+1, z1 );
s.vertex( i+1, j, z1 );
// +Y side
s.vertex( i+1, j+1, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i, j+1, z2 );
s.vertex( i+1, j+1, z2 );
}
}
s.endShape();
return s;
}
void setup() {
size( 800, 600, P3D );
// leave a strip of 0 on the right and bottom
float [][] data = new float[N+1][N+1];
for( int j=0; j<N; j++ )
for( int i=0; i<N; i++ ) {
float x = 2.*i/N-1, y = 2.*j/N-1,
a = atan2( y, x ), r = sqrt(x*x+y*y);
data[j][i] = (1.1+cos(TAU*2*r+3*a) + random(.5)) * N/64;
}
s1 = genGrid( N, data );
for( int j=0; j<N; j++ )
for( int i=0; i<N; i++ ) {
float x = 2.*i/N-0.5, y = 2.*j/N-1.2,
r = sqrt(x*x+y*y);
data[j][i] = (1.1+cos(TAU*2*r) + random(.5)) * N/64;
}
s2 = genGrid( N, data );
}
void draw() {
background( 0, 32, 64 );
lights();
camera( 0, 0, N*1.2, 0, 0, 0, 0, 1, 0 );
perspective( PI/3, 1, N/4, N*4 );
push();
rotateY( TAU/5. );
translate( 0, 0, -N*0.35 );
rotateX( TAU/12. );
rotateZ( frameCount/115. );
shape( s1, -N/2, -N/2 );
pop();
push();
rotateY( -TAU/5. );
translate( 0, 0, -N*0.35 );
rotateX( TAU/12. );
rotateZ( frameCount/115. );
shape( s2, -N/2, -N/2 );
pop();
fill( 255 );
camera();
perspective();
text( nf( frameRate, 0, 2 ), 10, 20 );
}
Adding color doesn’t seem to slow it down any:
int N = 64;
PShape s1, s2;
PShape genGrid( int N, float [][] data ) {
float c = 2.6*N/32;
PShape s = createShape();
s.beginShape(QUADS);
s.noStroke();
for( int i=0; i<N; i++ ) {
// -Y side
float z2 = data[0][i];
s.fill( data[0][i]/c, 0.5, 1 );
s.vertex( i+1, 0, 0 );
s.vertex( i, 0, 0 );
s.vertex( i, 0, z2 );
s.vertex( i+1, 0, z2 );
}
for( int j=0; j<N; j++ ) {
float z0, z1, z2;
// -X side
z1 = data[j][0];
s.fill( data[j][0]/c, 0.5, 1 );
s.vertex( 0, j, 0 );
s.vertex( 0, j+1, 0 );
s.vertex( 0, j+1, z1 );
s.vertex( 0, j, z1 );
for( int i=0; i<N; i++ ) {
z0 = z1;
z1 = data[j][i+1];
z2 = data[j+1][i];
// +Z top
s.fill( data[j][i]/c, 0.5, 1 );
s.vertex( i, j, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j, z0 );
// +X side
s.fill( data[j][i+(z0>z1?0:1)]/c, 0.5, 1 );
s.vertex( i+1, j, z0 );
s.vertex( i+1, j+1, z0 );
s.vertex( i+1, j+1, z1 );
s.vertex( i+1, j, z1 );
// +Y side
s.fill( data[j+(z0>z2?0:1)][i]/c, 0.5, 1 );
s.vertex( i+1, j+1, z0 );
s.vertex( i, j+1, z0 );
s.vertex( i, j+1, z2 );
s.vertex( i+1, j+1, z2 );
}
}
s.endShape();
return s;
}
void setup() {
size( 800, 600, P3D );
colorMode( HSB, 1, 1, 1 );
// leave a strip of 0 on the right and bottom
float [][] data = new float[N+1][N+1];
for( int j=0; j<N; j++ )
for( int i=0; i<N; i++ ) {
float x = 2.*i/N-1, y = 2.*j/N-1,
a = atan2( y, x ), r = sqrt(x*x+y*y);
data[j][i] = (1.1+cos(TAU*2*r+3*a) + random(.5)) * N/32;
}
s1 = genGrid( N, data );
for( int j=0; j<N; j++ )
for( int i=0; i<N; i++ ) {
float x = 2.*i/N-0.5, y = 2.*j/N-1.2,
r = sqrt(x*x+y*y);
data[j][i] = (1.1+cos(TAU*2*r) + random(.5)) * N/32;
}
s2 = genGrid( N, data );
}
void draw() {
background( 0.6, 1, 0.25 );
lights();
camera( 0, 0, N*1.2, 0, 0, 0, 0, 1, 0 );
perspective( PI/3, 1.*width/height, N/4, N*4 );
push();
rotateY( TAU/5. );
translate( 0, 0, -N*0.35 );
rotateX( TAU/12. );
rotateZ( frameCount/115. );
shape( s1, -N/2, -N/2 );
pop();
push();
rotateY( -TAU/5. );
translate( 0, 0, -N*0.35 );
rotateX( TAU/12. );
rotateZ( frameCount/115. );
shape( s2, -N/2, -N/2 );
pop();
fill( 0, 0, 1 );
camera();
perspective();
text( nf( frameRate, 0, 2 ), 10, 20 );
}