Compute Vertex Normals for Buffer Geometry in threejs
The process of creating a custom buffer geometry, or mutating a built in geometry in threejs might be a little involved, but still there is only so much to be aware of to get started at least. The first step might be to work out the positions attribute which is the values for the actual points in space. However after the position array is in a good idea to also work out what the deal should be with the normals attribute.
The normals attribute is one of many core attributes of a buffer geometry class that are needed in order to get geometry to look the way that one will typicaly want it to with mesh objects, rather than point or line objects. With points and lines all the one really needs are position attributes, and then maybe additional attributes that are used to mutate the position attribute. However with mesh objects there is a need to know what side of a face is the front side of the face, and with that said the normals attribute is how to go about doing just this. In some cases I might have to work out the values of the normal attribute manually, however in most cases just calling the compute vertex normals method of the buffer geometry class will work just fine. With that said this post will be on the use of the compute vertex normals attribute method of the buffer geometry class in threejs.
The compute vertex normals method and what to know first
Read up more on buffer geometry in general
This is a post on just one method of the over all greater class that is the buffer geometry class. There is a whole lot of ground to cover with just this one class alone, so it might be a good idea to also check out my main blog post on the buffer geometry class as well.
The source code examples in this post are on Github
The source code examples that I write about here in this post can be found in the for post folder of my test threejs repository on Github. This is also where I am parking the source code for my many other post on threejs, as well as many more demos that I also have parked there on all kinds of other topics that have to do with the over all librray that is threejs.
Version numbers matter with threejs
The version of threejs that I was using when I first wrote this post was r135, and the last time I came around to edit this post a little I was using r146. I have got myself into the habit of also making sure I write down what version of threejs that I am using when writing a post on a threejs example or two. Code breaking changes are made to the library often so it makes sense to always check what version of threejs you are using and how to compares with the blog post, or any online resource that you are reading.
1 - Some Basic examples of custom geometry and adding normals by way of compute vertex normals method
For this very first section I will be starting out with some very simple custom geometry examples. Some of these will not have a normal attribute at all that will serve as just a way to outline what can be done when working with a geometry that just has a position attribute alone. After that I will be getting into some examples where I do in fact quickly add a nomal attribute by way of the compute vertex normals method.
1.1 - Just starting out with a position attribute
For this very first basic example I am making a custom geometry that just has a position attribute and no normal attribute at all. So the this kind of geometry will not work so great with most mesh materials, at least not with default options and not without additional attributes anyway. So for this first example I will not be using a mesh object but rather a point object.
To start to create a geometry from the ground up then I call the THREE.BufferGeometry constructor function and then store the result from that to a variable. Next I will want to have at least a position attribute for this new blank buffer geometry so I will want an array for the x, y, and z values for each point in space that I want. For this first example I am just making a single triangle, so I will want three numbers for each point which will be a total of nine numbers in the array. Once I have my points data array I can use this to create a buffer attribute and set that as the position attribute of the buffer geometry.
1.2 - Basic compute vertex normals method example
When working with one of the built in geometry constructors the normals are worked out for me as that is part of making a comprehensive geometry constructor function. However when making a custom geometry from the ground up I will of course have to make attributes one way or another on my own. For example of the compute vertex normals method I am then just making a very simple geometry of a single triangle, and then calling the compute vertex normals method of the buffer geometry as a way to go about creating the normals attribute. Once I have a geometry with a position and normal attribute then the faces of the geometry will have a front face, and will also work with light sources.
So now that I have a normals attribute with this geometry I can now use a light source and see the material when using a material like that of the standard material with a light source. Although that might be the case there is still one additional attribute that I will need to add to the geometry in order for this to be a done deal in terms of the core set of attributes that are needed which would be the uv attribute. However for the sake of this post I think I should first cover a few more examples that focus more so on the state of this normals attribute and how to know what the state of it is.
2 - The THREE.VertexNormalsHelper
Here I have two plane geometries both of what I am mutating over time in the same way, but with one I am calling the compute vertex normals method and with the other I am not. On top of that I am also using the vertex normals helper to show what the deal is with the state of the normals for each geometry. It is also possible to see that there is indeed a clear differences with the textures.
The compute vertex normals method will work just fine for most cases as a way to create, or update the normals attribute of a buffer geometry instance. However there are some cases in which I might need to manually edit these values also, so I can not just call this method and be done with it all the time.
The general though process that I have when making a geometry is that first I need to just work out the positions attribute, then I need to get the normals attribute working as it should. However there is then the question of what the next step is after the positions and normals attribute are looking good. With that said I would say that the next thing I would want to figure out would be the uv attribute which is important when it comes to working out what the offsets of textures should be. There are some additional things after that as well though such as what the deal should be when it comes to groups, and material index values when using an array of materials to skin a mesh object rather than juts one.