# Drawing and orbiting a shape with many vertices

**URL:** https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375
**Category:** Coding Questions
**Created:** [May 30, 2021, 6:03pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375 "2021-05-30T18:03:05Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![hardwhere](https://avatars.discourse-cdn.com/v4/letter/h/ce73a5/32.png) [@hardwhere](https://discourse.processing.org/u/hardwhere)
#### Post date: [May 30, 2021, 6:03pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/1 "2021-05-30T18:03:05Z")

</div>

Hello! I’m drawing a shape with thousands of vertices in my draw() function; it’s just a line drawing connecting many vertices. I’d like to then orbit around this shape with e.g. the [easycam library](https://diwi.github.io/p5.EasyCam/). I’m able to do this, but framerate drops to ~0.3 fps. Is there a smarter way to do this? The shape won’t change during runtime, so I was thinking that something like [model()](https://p5js.org/reference/#/p5/model) would be useful, but I’m unsure of how to do this with a custom shape. I spent a good while googlinig this, but couldn’t seem to come up with the right search terms, so any advice or or resources pointing me in the right direction are greatly appreciated!

Thank you!

---

<div class="post-metadata">

### Author: ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)
#### Post date: [May 30, 2021, 9:26pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/2 "2021-05-30T21:26:55Z")

</div>

Hi,

Welcome to the forum! 😉

How many vertices do you need to draw?

If the shape doesn’t change, it might not be faster because it depends on how much time the computer takes to compute the curve points you are drawing. If you are doing an expensive computation to compute the line then yes but if you have a lot of vertices to draw it’s not the same issue.

Also it’s not entirely related to your question but you might want to read this previous thread about rendering on the GPU :

> [@Making use of the GPU to render huge amount of objects](https://discourse.processing.org/t/making-use-of-the-gpu-to-render-huge-amount-of-objects/26267):
>
> Hi, I’m new to p5.js and WebGL, so I’m not sure if I’m using the right terminology. Let’s start with the problem: We’re currently displaying a map of objects (simple rectangles with text in them, plus some single lines). Unfortunately, the number elements can go up to 25,000, probably even more, which completely crushes the performance. At the moment, we do all the draw calls in the draw() function, which I assume, is the main problem. In an older version, there’s a manual check, if an objec…

---

<div class="post-metadata">

### Author: ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)
#### Post date: [May 31, 2021, 9:18am UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/3 "2021-05-31T09:18:04Z")

</div>

Rendering p5.Geometry objects is indeed much more efficient than either drawing triangles with beginShape/endShape, or drawing lots of individual primitives (like `box` and `plane`). The reason for this is that p5.js takes p5.Geometry objects and turns them into vertex buffers which it caches and uses to render the model each time it is referenced.

One option is to create a 3d model file (such as a Wavefront .obj file, which you can create with Blender for example), load it with loadModel and render it with model. However if you want to create your model dynamically this is possible too. You just need to create a p5.Geometry instances and populate it’s `vertices` and `faces` arrays. Here’s an example of a sketch that demonstrates rendering an Icosahedron both with beginShape/endShape and with p5.Geometry (runnable version [here](https://openprocessing.org/sketch/1208594)):

```auto
const PHI = (1 + Math.sqrt(5)) / 2;

let vertices = [
  [0, 1, PHI],

  [PHI, 0, 1],
  [0, -1, PHI],
  [-PHI, 0, 1],
  [-1, PHI, 0],
  [1, PHI, 0],

  [PHI, 0, -1],
  [1, -PHI, 0],
  [-1, -PHI, 0],
  [-PHI, 0, -1],
  [0, 1, -PHI],

  [0, -1, -PHI],
];

let useModel;
let geom;

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  useModel = createCheckbox("Use Model?");
  useModel.position(10, 10);
  useModel.style('color', 'white');
  
  geom = new p5.Geometry(1, 1, constructIcosahedron);
  // This is used as the key for caching vertex buffers. Make sure it is unique.
  geom.gid = 'icosahedron';
  // Automatically calculate normals based on faces.
  geom.computeNormals();
}

// This callback is invoked by the p5.Geometry constructor. It must populated
// the vertices and faces arrays. It can also populate the uvs array and
// calculate normals.
function constructIcosahedron() {
  for (let v of vertices) {
    this.vertices.push(createVector(...v));
  }
  for (let i = 0; i < 5; i++) {
    let n = (i + 1) % 5;
    this.faces.push([
      i + 1,
      i + 6,
      n + 6
    ]);
    
    this.faces.push([
      i + 1,
      n + 1,
      0
    ]);
  }
  for (let i = 0; i < 5; i++) {
    let n = (i - 1);
    if (n < 0) {
      n = 4;
    }
    this.faces.push([
      i + 6,
      i + 1,
      n + 1
    ]);

    this.faces.push([
      i + 6,
      n + 6,
      11
    ]);
  }
}

function draw() {
  background(0);
  orbitControl(2, 2, 0.01);
  directionalLight(200, 200, 200, 0.5, -0.5, -1);
  directionalLight(200, 50, 50, 1, -0.5, 0.5);
  directionalLight(50, 50, 200, -0.5, 1, -0.5);
  

  scale(100);

  if (useModel.checked()) {
    model(geom);
  } else {
    beginShape(TRIANGLES);
    for (let i = 0; i < 5; i++) {
      vertex(...vertices[i + 1]);
      vertex(...vertices[i + 6]);
      let n = (i + 1) % 5;
      vertex(...vertices[n + 6]);

      vertex(...vertices[i + 1]);
      vertex(...vertices[n + 1]);
      vertex(...vertices[0]);
    }
    for (let i = 0; i < 5; i++) {
      vertex(...vertices[i + 6]);
      vertex(...vertices[i + 1]);
      let n = (i - 1);
      if (n < 0) {
        n = 4;
      }
      vertex(...vertices[n + 1]);

      vertex(...vertices[i + 6]);
      vertex(...vertices[n + 6]);
      vertex(...vertices[11]);
    }
    endShape();

    push();
    strokeWeight(8);
    for (let vert of vertices) {
      stroke(...vert.map(c => map(c, -PHI, PHI, 0, 255)));
      point(vert[0], vert[1], vert[2]);
    }
    pop();
  }
}

```

---

<div class="post-metadata">

### Author: ![hardwhere](https://avatars.discourse-cdn.com/v4/letter/h/ce73a5/32.png) [@hardwhere](https://discourse.processing.org/u/hardwhere)
#### Post date: [June 1, 2021, 7:44pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/4 "2021-06-01T19:44:54Z")

</div>

Oh wow, this is terrifically helpful! I was able to get something up and running with your helpful example, at 60 fps no less! There wasn’t much documentation in the p5 reference, so this is greatly appreciated.

A brief follow-up question (and I can start a new question if that’s better): is there an easy way to determine the value for detailX and detailY when declaring the new p5.geometry? I’ve found that they should multiply to be the number of vertices (i.e. detailX +1 \* detailY +1 = geom.vertices.length), and the order of the two matters (a tall object should have detailY \> detailX, and vice versa). But determining detailX and detailY in this way feels overly complicated.

Thanks again for your help!

---

<div class="post-metadata">

### Author: ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)
#### Post date: [June 1, 2021, 8:02pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/5 "2021-06-01T20:02:28Z")

</div>

In the “constructGeometry” callback you can use `this.detailX` and `this.detailY`, and these will be the values you passed as the first to parameters to `new p5.Geometry()`. These parameters are mostly intended for procedurally generated geometry such as cylinders and spheres where you can produce different numbers of faces to more accurately represent the shape. Or in cases like `plane` they allow you to add arbitrary numbers of subdivisions so that you have additional vertices that might be transformed with a vertex shader. They are also used by the `computeFaces` and `averageNormals` functions on `p5.Geometry` but again these are mostly intended for use with the built in procedural primitives. Unless you have a good reason for supporting different levels of detail with your geometry generation code I would recommend just leaving these values as 1.

I really should write a tutorial on this topic. You are right that it is poorly documented. I figured it out by reading the source code for [p5.Geometry.js](https://github.com/processing/p5.js/blob/main/src/webgl/p5.Geometry.js) and [3d\_primitives](https://github.com/processing/p5.js/blob/main/src/webgl/3d_primitives.js)

---

<div class="post-metadata">

### Author: ![hardwhere](https://avatars.discourse-cdn.com/v4/letter/h/ce73a5/32.png) [@hardwhere](https://discourse.processing.org/u/hardwhere)
#### Post date: [June 1, 2021, 8:11pm UTC](https://discourse.processing.org/t/drawing-and-orbiting-a-shape-with-many-vertices/30375/6 "2021-06-01T20:11:24Z")

</div>

Thanks! Interesting- after generating my geometry, using values of 1 seem to not display anything on the screen whereas using bigger numbers (in my case, (100, 140)) shows the object correctly… I’ll keep playing around with this!
