Seemingly Simple 3D Animation Running Very Slowly

I am fairly new to Processing and am trying to draw 3D shapes and do what seems to be a fairly simple animation. However, the performance is very poor (the animation speed is not uniform - slows way down and speeds up) and the sketch uses 50 to 80 percent of my MacBook Pro M1’s CPU.

I’m not sure if using a PMatrix3D the way I am is recommended practice. The reason for that is I wanted to be able to draw a quad strip between polygons that have been translated and rotated independently of one another, and you cannot call any transformations while building a shape (between beginShape() and endShape()) So this seemed like a pretty straightforward way of making that work.

Apologies if there is something obviously wrong here, or if drawing a 3D object of this complexity is simply exceeding the limits of Java or Processing.

ArrayList<ArrayList<PVector>> polygons;
PMatrix3D matrix;
int numberPoints = 4;

void setup() {
   size(640, 480, P3D);
   smooth();
   polygons = new ArrayList<ArrayList<PVector>>();
   matrix = new PMatrix3D();
}

void draw() {
  background(255);
  lights();
  
  translate(width/2, height/2, 0);
  rotateY(radians(frameCount));
  
  PVector center = new PVector(0, 0, 0);
  int crossSectionNumberPoints = 5;
  float crossSectionRadius = 20;
  float radius = 100;
  
  if (frameCount % 10 == 0) {
    if (numberPoints == 50) {
      numberPoints = 4;
    } else { 
      ++numberPoints;
    }
  }
 
  polygons.clear();
  matrix.reset();

  matrix.translate(center.x, center.y, center.z);
  matrix.rotateZ(radians(-90));
  
  ArrayList<PVector> shapeVerticesBase = polygonVertices(0, 0, crossSectionRadius, crossSectionNumberPoints);
   
  float angle = TWO_PI / numberPoints;
  float angleTotal = 0;
  for (int pointIndex = 0; pointIndex < numberPoints; ++pointIndex) {
    matrix.rotateX(radians(90));
    matrix.rotateY(angleTotal);
    matrix.translate(radius, 0, 0);
    
    polygons.add(transformVertices(shapeVerticesBase, matrix));
    
    matrix.translate(-radius, 0, 0);
    matrix.rotateY(-angleTotal);
    matrix.rotateX(radians(-90));
    
    angleTotal += angle;
  }
  
  for (int i = 0; i < polygons.size() - 1; ++i) {
    PShape s = buildQuadStripFromPolygons(
      polygons.get(i),
      polygons.get(i + 1)
    );
    shape(s, 0, 0);
  }
  PShape s = buildQuadStripFromPolygons(
    polygons.get(polygons.size() - 1),
    polygons.get(0)
  );
  shape(s, 0, 0);
}

PShape buildQuadStripFromPolygons(
  ArrayList<PVector> polygon1,
  ArrayList<PVector> polygon2) {
    
  PShape shape = createShape();
  shape.beginShape(QUAD_STRIP);
  
  for (int i = 0; i < polygon1.size(); i++) {
    shape.vertex(
      polygon1.get(i).x,
      polygon1.get(i).y,
      polygon1.get(i).z
    );
    shape.vertex(
      polygon2.get(i).x,
      polygon2.get(i).y,
      polygon2.get(i).z
    );
  }
  
  shape.vertex(
    polygon1.get(0).x,
    polygon1.get(0).y,
    polygon1.get(0).z
  );
  shape.vertex(
    polygon2.get(0).x,
    polygon2.get(0).y,
    polygon2.get(0).z
  );
  
  shape.endShape();
  return shape;
}

ArrayList<PVector> transformVertices(ArrayList<PVector> vertices, PMatrix3D matrix) {
  ArrayList<PVector> tVertices = new ArrayList<PVector>();
  PVector tVertex = new PVector();
  for (PVector vertex : vertices) {
    matrix.mult(vertex, tVertex);
    tVertices.add(new PVector(tVertex.x, tVertex.y, tVertex.z));
  }
  return tVertices;
}

ArrayList<PVector> polygonVertices(float x, float y, float radius, int npoints) {
  ArrayList<PVector> vertices = new ArrayList<PVector>();
  float angle = TWO_PI / npoints;
  float angleTotal = 0;
  for (int pointIndex = 0; pointIndex < npoints; ++pointIndex) {
    vertices.add(new PVector(
      x + cos(angleTotal) * radius,
      y + sin(angleTotal) * radius,
      0
    ));
    angleTotal += angle;
  }
  return vertices;
}

It stutters a lot for me too (for so few polygons…). Processing spends 96% initialising buffers during shape() which doesn’t seem right to me, but I’ll leave to someone more knowledgeable about P3D mode.

Hello @monty86,

Grouping the shapes provided excellent performance.

Changes to your code:

  surface.setTitle(str(frameRate));
  
  PShape torus = createShape(GROUP);
  
  for (int i = 0; i < polygons.size() - 1; ++i) {
    PShape s = buildQuadStripFromPolygons(
      polygons.get(i),
      polygons.get(i + 1)
    );
    //shape(s, 0, 0);
    torus.addChild(s);
  }
  PShape s = buildQuadStripFromPolygons(
    polygons.get(polygons.size() - 1),
    polygons.get(0)
  );
  //shape(s, 0, 0);
  torus.addChild(s);
  shape(torus, 0, 0);

References:

https://processing.org/tutorials/pshape
https://processing.org/reference/PShape.html

image

:)

Thank you VERY, VERY much.

That is the key insight I was lacking :smile:

2 Likes