The use of the Vector3 class instances in three.js is a major part of the process of doing much of anything in three.js. There is not just the geometry used with a material to compose a mesh object when it comes to vectors, the position property in the Object3d class is an instance of Vector3. This position property is used to set the position of mesh objects, cameras, and a whole lot of other objects.
However what if I just want to work with a collection of vectors, and have some kind of way of just displaying some points in space rather than lines, or a solid object. Maybe there is a few ways of going about doing that actually such as just observing the position property of a mesh as a point in space, and just using built in geometry constructors for the mesh such as the Sphere geometry constructor to just serve as some geometry to surround this point of interest. When I think about it for a moment maybe that kind of approach would be a good idea actually. However there is also the Points Constructor that can be used with the Special Points Material that is put in place just for this purpose of just drawing some points in space.
There is always at least a few different ways of going about doing something, I can not say that I bother with the points material that much when it comes to working on actual projects. So in this post I will of course be going over a few examples of the Points Constructor, but I will also be going over some other examples of this sort of thing involving collections of points in space.
So although I will not be getting into detail about the basics of three.js here, let alone everything else that you should be up to speed with before reading this. In this section I will be briefly be going over a few things that you should know, or many read up a bit more on before continuing with the Points Constructor and the Points material.
The source code examples that I am writing about in this post can also be found in my test threejs repo on Github.
When I first wrote this post back in May of 2018 I was using version r91 of three.js, and the last time I got around to editing this post I was using r140. Sense then a number of code breaking changes have happened when it comes to using the geometry constructor rather than the Buffer Geometry constructor. The old Geometry constructor has been removed from three.js as of version r125, so the examples here have been updated to work with the buffer geometry constructor as well as versions other chances that have happened sense then.
Although built in geometries can be used with the Points material, more often than not I think that main reason why developers might be looking into the points material and the Points constructor is to get into making custom geometries. So it would make sense to also look into the Buffer Geometry constructor at some point, maybe before or around the same time as starting to work with the Points Martial.
The Mesh is something that binds everything together into a single package of sorts, and it has properties and methods that are appropriate for it. In the above example I am just using the Box geometry constructor as a way to just go about quickly creating a geometry, and I am using that geometry with the basic material as a way to go about skinning that geometry. However when it comes to using the THREE.Points constructor in place of THREE.Mesh, I need to create a custom instance of Buffer Geometry.
1 - The basics of Points and the Point material vs Mesh Constructors, and basic Three.Points Constructor example
If you have made at least a few basic three.js demos you might be at the point where you understand that at least part of the process is to create and add a Mesh object and add that object to a scene object. That scene object is then passed to a renderer along with a camera to create a render instance that can then be used to draw to a canvas element. This Mesh Object is composed of a Geometry, and at least one material to be used when rendering that Geometry.
The THREE.Points class is then just a different kind of Mesh that is used to just draw points of a geometry in the position attribute. One thing about this Points constructor is that it can just me used just like with Mesh objects in that I can just pass any buffer geometry to it. However the main different from that comes with the material to use with the Points Constructor which is a situation in which I just have the points material to work with.
The points constructor is like that Mesh constructor only it is just the position attribute of a Buffer Geometry instance that will be mainly what is used in rendering. This geometry that I give the THREE.Points constructor could be a custom geometry like the one on the documentation page of the THREE.Points constrictor on the three.js website. However it can also be one of the geometries that is created and returned by one of the Built in geometry constructors such as the THREE.SphereGeomerty constructor.
So in other words the points constructor is just a more primitive kind of mesh, that can only be used with a special points material, but aside from that an instance of THREE.Points is very similar to that of THREE.Mesh instances. Just like the that of A mesh and Instance of Points is based on the Object3d class, so when it comes to positioning and rotating the Points instance all of that is more or less the same as Mesh. Also it is still and instance of buffer geometry that is passed as the first argument, that can be created by using the Buffer Geometry constructor directly, or by using one of the built in constructors, it is just that many of the attributes that would be used in the Mesh constructor are ignored.
Although I might often want to just pass a buffer geometry that I all ready have to the Points constructor In many cases I might have an array of Vector3 class instances that I would like to create a buffer geometry from. I will then want to use the buffer geometry that is created from this array of Vector3 class instances with the Points Constructor. The general process of doing this would be to create a typed array from the array of vector3 class instances that I can then use with the set attribute method of the Buffer geometry class to create the position attribute for the geometry.
The nice thing about Points is that it is just the position attribute that I care about with this. When it comes to mesh objects there is also the normal, and uv attributes that I would want to set up. However this is a post on the points material so I will not be getting into any of that here. However I do in any case see the position attribute as the first attribute of interest in creating a custom geometry so this is always a good starting point.
Okay so I covered an example in which I create a buffer geometry from an array of vector3 class instances. However what if I want to create an array of Vector3 objects, use the power of the various methods to work with in that class to mutate the values of the vector3 objects, and then convert that to a geometry? One way to do this is to loop over the array of the position attribute, when doing so I can use the count value to know what the number of points is. For each point then I can use the getX, getY, and getZ methods if the Buffer Attribute class to get the various values that I can then in turn use to create my array of vector3 objects.
Once I have my array of vector3 class instances I can loop over them and use methods like normalize, applyEuler, and multiplyScalar just to name a few to mutate the values. I can then do the same as before with the methods I covered before hand to crate a buffer geometry instance from this array of mutated vector3 objects.
2 - The Points Material and creating a custom geometry with the Buffer Geometry Constructor, and Rand Float Spread
Now that I have covered the basics of the TREE.Point constructor, and how it compares to the Mesh Constructor it is now time to start to look at a few more examples of the Points constructor and of course the Points material. One not so hard yet interesting example that comes to mind with this would be to just have a whole bunch of random points in a given range.
In this example I am using the THREE.Math.randFloatSpread function to create values between zero and a given max range. I then will want to create an instance of the Buffer Geometry constructor, and create a position attribute for the geometry. The array or points will then be passed to the set attribute method of the buffer geometry instance. After that it is just a matter of passing the instance of buffer geometry to the THREE.Point constructor as the value for the first argument, followed by an instance of the Points material.
The next step with this is starting to experiment with creating custom geometries, and just looking at the state of the points alone. With that said there is starting to work out expressions for creating the array of values to be used just for the position attribute of an instance of Buffer Geometry. The full process of making a geometry instance that will work well with THREE.Mesh is a little involves, and working out the position array is just one part of the process. However when it comes to just using the THREE.Points constructor and the Points material I can just focus on the points in space, and that is all. In this example I was paying around with some expressions that result in the formation of a spiral like pattern of points.
There is a great deal more to look into when it comes to making a solid custom geometry, however maybe one of the first things that should be worked out is the position of the vertices. Just working out that logic with the use of the Points constructor is then a good starting point, and then from there it is just a question of adding all the additional properties that are needs when it comes to drawing triangles between the points, and setting material index values as well as a uv array.
The points material will work just fine for situations in which I just want to get a basic visual representation of the points of a geometry alone. However it goes without saying that there are some draw backs with using the points material as well as the corresponding points constructor over the mesh constructor and the lengthy array of choices for materials with mesh objects. One major draw back is that I can not do anything with light, and yet another draw back is that I do not have control over the shape that will be used with each point. For example if I want to have a sphere like shape for each point and also show at least a little depth for each sphere for each point then I am going to want to go with mesh objects.
To go about creating a mesh for each point in a geometry I will want to find a way to create an array of Vector3 instances from the position property of a geometry, or use methods like getX, getY, and getZ of the position attribute along with the use of the count property of the position attribute. For this example I am doing the later of these two to create Vector3 instances as needed. And for each vector3 instance that I create I copy that Vector to the position property of a new mesh object that I am making for each point. When doing so I can use any geometry I want for each point, such as the Sphere geometry constructor, also I can use any material that I want including potions that respond to light sources.
Working with just the position attribute of buffer geometry along with the Points and Points Material can be kind of fun. That is once one gets past all the dull stuff to start creating interesting artful work and animations. For this example I made a little animation loop in which I take a Torus Geometry and explode it outward into all kinds of various points, and then back again.
So the points material is an interesting alternative to the typical basic or standard material that I often use in my basic project examples that I have made thus far with working with the typical Mesh rather than points class. There should be at least one such option when it comes to just having a way to see the location of points in a geometry, and the points material seems to work fine when it comes to this. However there are a number of draw backs from using the Points class, and I think that I often will want to use a mesh instance even in situations in which I am interested in the points, by using a geometry positions attribute as a way to set position values for a collection of mesh objects.