Tutorial: Using p5.Geometry to create fast 3D graphics

I’ve answered a number of questions recently about the performance of complex 3D shapes in p5.js (@J_Silva and @salmans911 in particular), and I promised a more in depth explanation of how to use p5.Geometry. Without further ado, here it is.

If there are additional questions, or if anything is unclear in the article, or if there are typos or errors in the article, please let me know.



Hey Paul,

I just went through the article, and it is super detailed and clear especially the examples really help understand what is going on. I think you’ve just made p5.Geometry more accessible to people who are interested in it but can’t quite understand it fully (like me ofc :sweat_smile:). You could try to talk to the p5.js team to put your article as a reference point for p5.Geometry on the p5.js site.


Great tutorial!
I have still a question though. Let’s say we have a tube instead of a Mobius strip with a detailX = 60 and detailY = 20, and I want to have a smaller diameter in the middle. How do I ‘narrow’ this in just one model? Or do I need to build one on top of the other?

If you want to use computeFaces() you’re a bit limited because each strip of vertices is connected to the next one by a strip of triangles, and you can only have detailY strips of triangles (detailY + 1 strips of vertices). However, so long as detailY is >= 4, then you could do 1 strip for the top cap, 1 strip for the bottom cap, and (detailY - 2) / 2 for the inside and outside of the tube/hollow cylinder.

1 Like

Here’s a working “tube” example:

One downside of the combo of computeFaces() and computeNormals() here is that there is a noticeable seam where the normals are not averaged between the faces on the first strip and the last strip.


Thanks again. So I can build the stripes on top of each other within one P5.Geometry but they will be connected as one mesh. As for the second part of the question, I think I didn’t make myself clear. With ‘narrowing’ I meant a shape of two truncated cones placed on top of each other. I searched in the documents to see how the cone() function is generated, and I have no idea why they didn’t implement a cone function with the full parameter list, including the top diameter to make truncating possible. So I wrote the code as a new p5.Geometry function. I will post it here if someone needs it.

createTruncatedCone(bottomRadius, topRadius, height, detailX, detailY, bottomCap, topCap)

code here.


It looks like you may have found a solution to your multple-truncated-cones question. However, I did want to suggest an alternate approach. Which is to describe your shape as a polyline that is revolved around an axis (this shape definition is called a lathe, referencing the woodworking tool).


So nice! It’s a complete shape-building tool. I will study this carefully.
Mahalo nui loa!

Hi. Excellent tutorial. I managed to code a pyramid, but I would like to build shapes with multiple cones as well. The ‘lathe’ sketch above is good, but a little complicated for me.
J_Silva did you succeed in writing the code?

Hi Clark. Yes, I did. The code below is an object from a larger sketch, which uses 60 of them, so I needed to code it as an object because writing it in vertexes between begin/endShape would simply slow down and stop the sketch. It does not compute the uvs array to be able to use textures, only the vertexNormals necessary to reflect light. You need at least three cones to let it work. From there on you add one cone at a time and adjust the offset and more important the detailY value. (each cone has just one triangulation)
I hope it helps.


One thing to keep in mind is that only the first 56 lines of that sketch are the 3d geometry drawing code. The remainder is for the 2d line editing script. If you know the coordinates you want for the line then you can skip ignore all of that code and just set the coordinates you want as an array.

1 Like

Hi, thanks a lot for the beautiful tutorial.
I modified a little your ‘Height Map Geometry’ example to draw an height map of generated simplex noise instead of an image and it works as expected. But if I use detailX, detailY > 255 I have problem with filled draw while with only stroke is OK.

Here the output with detailX = detailY = 350 and stroke + fill.
Only stroke no problems.
detailX, detailY <= 255 no problems for both only stroke and stroke + fill.