Morph Attributes of buffer geometry objects
The morph attributes property of a buffer geometry instance will store an object which contains buffer attributes that are used to mutate the state of other buffer attributes of the geometry over time. Simply put it is a way to go about creating animation by having say additional position attributes for several other kinds of states for the points of a buffer geometry. These additional attributes that are used to morph a buffer geometry can contain absolute values foe each item, or they can be delta values that store a rate of change for each item as well.
Morph Attributes of buffer geometry and what to know first
This is a blog post on more attributes of buffer geometry objects in the javaScript library known as threejs. If you are fairly new to threejs this post my prove to be a little too advanced as there is a whole lot to be aware of before getting into this sort of thing. For one thing there is knowing a thing or two about what buffer attributes of buffer geometry objects are to begin with. So in this section I will be writing about a few quick key things that you might want to read up a bit more on before counting to read the rest of thing post.
Position and normal attributes only for WebGl1, color attributes as well with WebGl2 only.
Looking at the WebGlRenderer source code for threejs it would seem that position, normal, and color attributes are being updated by way of morph attributes. However if you are sticking with using webGl1 only, then it is just position and normals that will update.
Read up more on Buffer Geometry in general
There is a whole lot of ground to cover when it comes to buffer geometry in general before getting into this topic of morph attributes. So you might want to start out with my main blog post on buffer geometry for starters. I also have wrote blog posts on the position attribute of buffer geometry as well as on the index that is used to make it so one can reuse points in the position attribute as well.
Source code is also up on Github
The source code examples as well as additional assets that i am using in this post can be found in my test threejs repository on Github.
Version Numbers matter
When I first wrote this post I was using r146 of threejs.
1 - Some Basic Examples of using morph attributes
Before I start getting into some examples that are are some real over all examples of morph attributes in this section I will be starting out with a few very simple hello world style examples first. The general idea here is to create an additional buffer attribute with the same item size and count of items as the buffer attribute that I want to mutate. Then I create a property of the morph attributes object that is the same key as the name of the attribute I want to mutate and the value should be an array. I can then push this additional buffer attribute as an item of this array. Once that is all set and down it is just a matter of setting the morph targets influences alpha value to set how much an additional buffer attribute in the morph attributes array will impact the state of the buffer attribute I want to mutate.
Still confused? Well thats okay this is a little involved, but it is still only so hard, and maybe it would be best to just read some source code examples here. These examples will just involve one more attribute and I will be sticking to just the position attribute of the buffer geometry. Also for now I will be sticking to using built in geometry constructor functions, and also just keep these as simple static scenes as will in order to focus on just what is more important with this.
1.1 - Random points to move the points of a sphere to.
For this basic example I am creating a sphere geometry, and then creating a single buffer attribute of random points the count of which is the same as the position attribute of the sphere geometry. Some times one just has to start somewhere so this just seems like a real simple way to go about getting started with morph attributes.
Anyway after setting up my usual set of objects for any threejs project such as the scene object, camera, and renderer I start out with the geometry by calling the THREE.SphereGeometry constructor function. So then I have a sphere geometry with a position attribute of course, so now what I want to do is just create a new buffer attribute of random points for each point in the position attribute of this geometry. I can then set this new buffer attribute as the first element of an array for the position property of this morph attributes object of the geometry.
|
|
Once I have a more attribute set up for this geometry I can then use the morph targets influences array to set what the alpha value should be between the original position attribute state of the sphere, and these random points I made for each point in the sphere. For this example I am going with the mesh normal material and because I made the geometry with the sphere geometry constructor there is a normal attribute, but as I mutate the position attribute I will want to also update the normals. One way to quickly update the normals is to use the compute vertex normals method as I am doing in this example
1.2 - Box to sphere example
One of the first examples that I looked at to get an idea of how to do this was to look at the source code of one of the official threejs examples on more attributes that can be found here. This example was a good resource for getting started with buffer attributes, but I have found that it is just a little to complex for a basic getting started type example. So I remove some of the code that has to go with adding a twist and keep the code that has to do with just mutating the buffer geometry state from a box to that of a sphere.
|
|
2 - Custom geometry and morph attributes
Now that I have a few basic examples out of the way in this section I will be getting into a few more advanced examples not just of more attributes but many buffer geometry features for that matter. These examples will then involve creating a custom geometry from the ground up using hard coded javaScript array literals for the data. However some of the examples will also involve exporting this kind of data into a JSON format that can then be used with the buffer geometry attribute. With that said one of the goals here is to export how to go about making an over all model that will involve morph attributes.
2.1 - A custom geometry with more than one morph attribute
For this fist example and all the other examples in this section I am going to be making a very crude bird like model that contains just 12 points in the position attribute. I will then draw triangles using these 12 points by figuring out what the values should be for the index of the position attribute of the buffer geometry. So this geometry will contain just a few points, but it will still be enough to have some parts of the geometry that resemble wings, and the rest of what can be considered a kind of body. However what is really important here is just having a way to define not just one, but a few buffer attributes for this geometry. You see I would like to move the wings, move the head back and froth, and move the tail up and down. On top of all of this I would like to control the state of each of these Independently from each other.
|
|
2.2 - Making a non indexed geometry
Indexed geometry is great but one thing that I need to be aware of when making them is that it will not just reduce the count of points in the position attribute but also other attributes such as the normal attribute. This will result in just one vertex normal for each point which can result in rendering problems if I want to use the mesh normal material, or any material where the state of the normal attributes is of dire importance in rendering the state of the textures for each face. The good news with this though is that there is the to non indexed method of the buffer geometry that can be used to quickly create a non indexed geometry form an indexed one. I then have points for each triangle and with that independent vertex normal values as well so when I call the compute vertex normals method I get vertex normal values for each of these points that are not the same for each original vertex value.
|
|
So the mesh normal material is looking great as well as the animations. So now that this is all in great working state it is just a question of getting the uv attribute set for this as well at which point I can ad textures to the geometry.
Conclusion
So it would seem that morph attributes are a great way to go about defining some animations for a geometry. However they might still not be the end all way to go about mutating the state of a geometry over time. In some cases I might want to mutate one state of geometry to another, but not do so in a way in which all the points move in a steerage line from one set of values to another. When it comes to doing something like that I might still need to directly change the state of the arrays of buffer attributes and do so with a little custom javaScript code.