Making custom geometry in three.js
When I first wrote this post back in 2018 I was using threejs version r91 which had two constructor options for creating a custom geometry. One was the Buffered Geometry constructor, and the other was the Geometry constructor to which this blog post is about. So because this post is on the plain Geometry constructor that is now deprecated as r125+ of threejs, it would be best these days to look into my post on the Buffer Geometry constructor at this time. I do poke my head in here now and then to do a little editing, and clean up and expand code, but I do so using a revision of threejs that is now fairly out of date.
The examples here as of this writing will break in late versions of threejs which would be r125 or later. It might be possible to get the old Geometry constructor working on a late versions of threejs at some point in the future by making use of a file in the examples folder of the threejs github repository. The same has happened in the past with other features that where removed from the core of threejs, however at this time it might be best to just not use the Geometry constructor any more, and just learn how to use the Buffered Geometry constructor alone.
The old Geometry constructor in threejs, and what to know before hand
THE GEOMETRY CONSTRUCTOR IS NO MORE as of threejs revision 125+, so yes VERSION NUMBERS MATTER
Once again when it comes to using new versions of threejs that are of revision 125 or higher the Geometry constructor is no longer part of the core of threejs by itself. From now on it would make more sense to just directly work with buffered geometry as the only alternatives would be to use older versions of threejs, or get the Geometry constructor to work again by making use of some additional external file.
So yes version numbers matter big time when it comes to working with threejs, and with that said when I first wrote this post I was using threejs r91, and the last version of threejs that I bothered to do a little editing with the source code was r111 of threejs.
Geometry vs BufferGeometry
In threejs there is BufferGeometry, and then regular Geometry constructors. The reason for this is that the regular Geometry constructor is easier to work with as the vertices, faces, and so forth are stored directly. However this comes at a performance loss. Still if you are new to making custom geometry it would make sense to start with the regular Geometry first, then progress into the more advanced BufferGeometry to know how to make your projects run faster.
There are many built in geometry constructors that can be used to quickly make many simple, common, solid shapes like cubes, and spheres. However when getting into making an actual three.js project rather than just yet another simple rotating cube demo, there is going to be a need to have a way to make custom geometry. If you are using an older version of threejs, or you can some how get the old Geometry constructor working on a later version of threejs then maybe some of these examples of the old geometry constructor can still prove to be helpful.
BuferGeomeetry from Geometry
Now that the Geometry Constructor has been deprecated this might not be a topic of interest when it comes to updating older code that made use of the Geometry Constructor. Having a quick, duck tape like solution for this might be nice for starters, but ultimately the best way to do so would be to just use the buffered Geometry constructor. Never the less I will be covering this here when it comes to any and all future edits of this post for what it is worth.
As of r125+ it would seem that this method has been removed from the core of threejs. As such in late versions of threejs this is no longer an effective way of converting an old Geometry constructor instance into a buffed geometry instance as it will result in calling undefined.
If by chance you are using an older version of threejs that has this method, then of course it should still work assuming that it is there.
There is also THREE.Face3, and THREE.Vector3
So with new versions of threejs r126+ actually the THREE.Face3 constructor is no more also. In the buffer geometry class of new versions of threejs the features of face3 and now more or less part of what is now know as the groups array. So if you are using a new version of threejs there is no need to read up more on the Face3 constrictor, but you might want to learn what groups are if you intend to make your own geometry constructors.
There is another constructor that I am using in many of these examples and that is the THREE.Vector3 constructor which would seem to have survived the chopping block. Which is not surprising that is still a useful class when it comes to creating and working with vectors in threejs.
The source code examples here are on guthub
The source code examples here are up on my test threejs github repository. This is also where I am parking the source code for my many other posts on threejs as well.
1 - Basic three.js Geometry example.
The basic process is to first create an instance of Geometry by calling the constructor, and saving the instance of Geometry to a variable. Once you have your instance of Geometry you can now start adding some vertices to it, these are just points in space that are created using the Vector3 constructor.
After You have an array of vertices to work with you can start adding faces if it is a geometry that will be used with a Material that makes use of faces. This will be an array of Face3 instances that expect three arguments that are the index values of the vertices in which a face is to be drawn between 3 points. An easy way to do this is to think of it like connect the dots, each vertex has an index value to it, and you are just drawing triangles between them. However the order of the index values is important, so if you are running into issues that might be a reason why.
Once you have your vertices, and faces you might want to call computeVertexNormals, and normalize the geometry. More on that later.
Here is an example of what it is I am talking about here.
In this example I am repeating the use of Vector3, and Face3 constructors over and over again for each instance. However in more advanced examples you can of course get into making helper functions that will involve loops that will involve the use of these constructors in just one line of your code.
2 - Creating a helper method that returns a Geometry
3 - Normalizing Geometry
A common task to do when you have an off centered geometry, is to center it. In addition it may Also be desirable to have it set within a bounding sphere of area that has a radius of one, so that it is easily scaled up or down from there. To achieve this you will want to use the normalize method.
This is typically what I will always want to do with a geometry, after all it is going to be placed in a Mesh, at which point I will use methods that come with the mesh to move, and rotate the geometry further from there. Having the geometry centered to the origin will only be relative to the instance of Geometry that will be in a Mesh, not the over all Scene.
In Other words think of this Geometry as being relative to the center of a Cube, or Sphere if you prefer, and then you are going to move and rotate this object in a Scene that might contain many such objects. So chances are you are going to want it centered to this relative origin, and scaled to a certain standard.
4 - Scale and rotation of a geometry
If I want to scale a geometry, it can be done with the scale method method of the geometry instance. This is something that might typically be done only once if it is a static Geometry. There is also a scale property with the Mesh object that will be available when using the geometry, this is what should be typically used in a loop. However maybe getting into that would be a matter for a whole other post.
When it does come to working with the old geometry constructor I can then do something like this to normalize, scale, and rotate the geometry as a way to adjust the state of the geometry relative to the local space of the mesh object that will contain this geometry.
The geometry constructor was a good place to start when it comes to learning how to make custom geometry from code, and it still is when it comes to using older versions of threejs. However when it comes to working with later versions it is no longer an option, at least as of r125 for the moment. In the past when features where removed there was often files that would appear in the examples folder of the github repository that would bring that feature back by way of making that external file part of stack of a project. For example that was the case when it came to the removal of the 2d canvas renderer which can still be used, it is just no longer built into threejs itself. I assume that the same will happen with the Geometry constructor, and if so I will come around to editing this post again when it comes to using that.
In time I will likely update this post at least a few times when and if I become aware of more options when it comes to transitioning from using the Geometry constructor to bufferedGeomorty only.
Be sure to also read up more on Vector3, and Face3 if you have not done so before hand as these are also important constructors that are related to the Geometry constructor in three.js.