By Dave Pagurek, Austin Lee Slominski, Adam Ferriss
p5.js has a number of built-in basic shapes, like box()
and sphere()
. It can also render complex custom geometry, both from 3D model files or code. This tutorial will walk through how to import 3D models into p5.js, as well as how to create geometry from scratch.
Loading 3D models from file
Custom geometry can be imported into p5.js using either OBJ or STL files. These files are usually generated in a 3D modeling tool like Blender, which offers much more control when constructing a 3D scene. This is done using the loadModel()
method, which should be used within preload()
. Then, you can use the model()
function to draw the model, as demonstrated in the example below.
A common issue that can come up with custom models is scaling. Depending on how the model is constructed, it might be a very different size when drawn in p5.js, or be too small to be drawn at all. The loadModel()
method includes a normalize
parameter that will resize the model to something that works better in p5.js.
Note that there is currently no support for loading materials and colors from model files. You can add color, materials, and textures manually after loading a model.
Try this!
Try finding a 3D model online and integrating it into a sketch!
Creating procedural geometry
Geometry can also be defined procedurally using code. This is a great way to create geometry that moves or is formed using your own set of rules. There are a number of methods that can be used to create 3D geometry in a way that is similar to 2D drawing. For example, functions like quad()
, triangle()
, rect()
, and circle()
each have extra parameters that make it possible to use them in 3D.
There are other functions that offer greater control of the geometry. A shape can be defined point-by-point using beginShape()
, vertex()
, and endShape()
. The following example shows how these functions can be used to construct a 3D shape.
Try this!
Can you create a 3D bolt of lightning using beginShape(QUAD_STRIP)
?
Reusing procedural geometry
This method is great for creating custom shapes that change over time. Sometimes, you might only need a fixed shape or want an efficient way to draw a shape many times. For this, p5.js has a function called buildGeometry() to turn your custom shapes into the same format as a loaded model. If you are planning on making a particle system, this is a good tool to reach for.
It takes in a function that draws some shapes. It will then output geometry that you can draw with model() as often as you like.
Try this!
Try making a few snowflakes using buildGeometry
, and then use them to create a big snowfall!
Smooth shading
A normal is the direction that is perpendicular to the face, which helps p5.js calculate lighting across the surface.
As long as every vertex shared between touching faces has the same normal, then shading will look smooth. You can specify normals manually by calling normal(x, y, z)
before each vertex(x, y, z)
, but p5.js includes functionality to calculate these for you. The following example uses geometry.calculateNormals(SMOOTH)
to create a warped tube with smooth lighting.
Try this!
Try making a smooth, organic shape in p5. Can you create buildings in the style of Frank Gehry, built out of smooth, wavy strips?
Advanced geometry techniques
Sometimes, you need even more flexibility when making shapes. For example, sometimes you want vertices to be connected irregularly into faces rather than through a grid, or you want to use custom normals or texture coordinates calculated after having generated all your vertices. The p5.Geometry
class gives full flexibility in creating vertices, faces, texture coordinates, and normals. p5.js uses p5.Geometry
internally for loadModel()
and buildGeometry()
.
In 3D, a face refers to a collection of three points that make up a surface, giving our geometry the appearance of being solid. In p5.Geometry
, you create faces by:
- Putting all the points you will use into a big array in the
geometry.vertices
property, and remembering the order the points are added. - Putting sets of three indices at a time into the
geometry.faces
array. The index of a point refers to its position in the array, determined by the order in which it was added. Index 0 corresponds to the first point you added, index 1 corresponds to the second, index 2 corresponds to the third, etc.
The following example uses this method of creating vertices and faces to create a custom tetrahedron shape.
You can also push a p5.Vector
into the geometry.normals
array for each vertex you push into geometry.vertices
. However, you can still call geometry.computeNormals()
for custom p5.Geometry
just like you can for geometry built with buildGeometry()
.
Try this!
A tetrahedron is part of a group of shapes called Platonic solids. Try generating more of them as p5.Geometry
!
Conclusion
Now, you should be able to create custom geometry, making it possible to create unique shapes, both from other tools and from code. Spend some time working with a variety of 3D modeling tools so you can find the one that works best for you. If you find bugs please raise an issue on Github, or if you run into trouble, feel free to ask questions on Discord or the Processing Foundation Discourse forum.
Glossary
Procedural
Meaning that something is defined mathematically, instead of from stored data, like a file.
Model
A representation of geometry.
STL
STL (most often standing for “standard tesselation language”) is a file format for 3D models. It only stores information about the geometry.
OBJ
OBJ is an open file format that stores geometry data as well as some material and texture data. In p5.js, we are limited to its geometry, although an image can still be mapped to the surface using textures.
Vertices
The points of a shape that make up the corners of its faces.
Faces
The solid surface that is generated between three points.
Normals
The direction that is perpendicular to a face which is often needed when calculating lighting or using materials.
Normalization
Changing something so that it fits within a standard range.
Indices
Positions in the array of vertices. Faces reference vertices by these positions.
loadModel()
A p5.js function to load a shape from an OBJ or STL file.
p5.Geometry
A class that p5.js uses to store shapes.
model()
A p5.js function to draw a shape to the screen.
buildGeometry()
A p5.js function to record all the shapes that get drawn and save them into a new p5.Geometry
object.
computeNormals()
A method that can be called on p5.Geometry
to calculate the direction coming out of each face so that they don’t need to be manually created.
संबंधित संदर्भ
loadModel
एक p5.Geometry ऑब्जेक्ट बनाने के लिए एक 3D मॉडल लोड करता है। loadModel() OBJ और STL फ़ाइलों से 3D मॉडल लोड कर सकता है। एक बार मॉडल लोड हो जाने पर, इसे model() फ़ंक्शन के साथ प्रदर्शित किया जा सकता है, जैसा कि model(shape) में है। मॉडल को संसाधित करने में सहायता के लिए वैकल्पिक पैरामीटर के साथ loadModel() को कॉल करने के तीन तरीके हैं। पहला पैरामीटर, path, हमेशा फ़ाइल के पथ के साथ एक string होता है। स्थानीय फ़ाइलों के पथ सापेक्ष होने चाहिए, जैसे loadModel('/assets/model.obj')। 'https://example.com/model.obj'` जैसे यूआरएल को ब्लॉक किया जा सकता है ब्राउज़र सुरक्षा के लिए। कॉल करने का पहला तरीका loadModel() में फ़ाइल पथ के बाद तीन वैकल्पिक पैरामीटर हैं। पहला वैकल्पिक पैरामीटर, successCallback, मॉडल लोड होने के बाद कॉल करने के लिए एक फ़ंक्शन है। उदाहरण के लिए, loadModel('/assets/model.obj', HandleModel) मॉडल लोड होने के बाद handleModel() फ़ंक्शन को कॉल करेगा। दूसरा वैकल्पिक पैरामीटर, failureCallback, मॉडल लोड होने में विफल होने पर कॉल करने के लिए एक फ़ंक्शन है। उदाहरण के लिए, यदि लोड करते समय कोई त्रुटि होती है, तो loadModel('/assets/model.obj', HandleModel, HandleFairure) handleFairure() फ़ंक्शन को कॉल करेगा। तीसरा वैकल्पिक पैरामीटर, fileType, एक स्ट्रिंग के रूप में मॉडल का फ़ाइल एक्सटेंशन है। उदाहरण के लिए, loadModel('/assets/model', हैंडलमॉडल, हैंडलफेल्योर, '.obj') फ़ाइल मॉडल को .obj फ़ाइल के रूप में लोड करने का प्रयास करेगा। पी> कॉल करने का दूसरा तरीका loadModel() में फ़ाइल पथ के बाद चार वैकल्पिक पैरामीटर हैं। पहला वैकल्पिक पैरामीटर एक boolean मान है। यदि true पास हो जाता है, जैसे कि loadModel('/assets/model.obj', true), तो यह सुनिश्चित करने के लिए मॉडल का आकार बदल दिया जाएगा कि यह कैनवास पर फिट बैठता है। अगले तीन पैरामीटर हैं successCallback, failureCallback, और fileType जैसा कि ऊपर बताया गया है। कॉल करने का तीसरा तरीका loadModel() में फ़ाइल पथ के बाद एक वैकल्पिक पैरामीटर है। वैकल्पिक पैरामीटर, options, विकल्पों के साथ एक object है, जैसे loadModel('/assets/model.obj', options) में। options ऑब्जेक्ट में निम्नलिखित गुण हो सकते हैं: let options = { // Enables standardized size scaling during loading if set to true.
buildGeometry
सरल 3D आकृतियों से एक कस्टम p5.Geometry ऑब्जेक्ट बनाता है। buildGeometry() सरल आकृतियों से जटिल 3D आकृतियाँ बनाने में मदद करता है, जैसे कि sphere()। यह रेखाचित्रों को अधिक प्रभावशाली बनाने में मदद कर सकता है। उदाहरण के लिए, यदि स्केच चलते समय कोई जटिल 3D आकार नहीं बदलता है, तो इसे buildGeometry() के साथ बनाया जा सकता है। p5.Geometry ऑब्जेक्ट को एक बार बनाना और फिर उसे खींचना अलग-अलग टुकड़ों को बार-बार खींचने की तुलना में तेज़ चलेगा। पैरामीटर, कॉलबैक, नए p5.Geometry ऑब्जेक्ट के लिए ड्राइंग निर्देशों वाला एक फ़ंक्शन है। नया 3D आकार बनाने के लिए इसे एक बार बुलाया जाएगा। निर्माण के दूसरे तरीके के लिए beginGeometry() और endGeometry() देखें। ध्यान दें: buildGeometry() का उपयोग केवल WebGL मोड में किया जा सकता है। .
model
कैनवास पर एक p5.Geometry ऑब्जेक्ट बनाता है। पैरामीटर, model, खींचने के लिए p5.Geometry ऑब्जेक्ट है। p5.Geometry ऑब्जेक्ट को buildGeometry() के साथ बनाया जा सकता है, या beginGeometry() और endGeometry()। इन्हें loadGeometry() वाली फ़ाइल से भी लोड किया जा सकता है। ध्यान दें: model() का उपयोग केवल WebGL मोड में किया जा सकता है। .
p5.Geometry
A class to describe a 3D shape.