When I am working on threejs demos and simple project examples I will often get into a situation in which I might want to copy a mesh object. When doing so there is the idea of just copying the own properties of the mesh object, but often I will also need clones of all the child objects as well, there is also the geometry, and material that is used by the mesh that I might want to clone while I am at it.
Shallow cloning is creating an new object where it is more or less just the properties of the object itself that are copied, and not anything when it comes to nested objects that are values of the source object. Deep cloning then is then the general term for getting into the subject of what should and should not be copied when it comes to looping over all the nested properties of an object. Things can prove to get a little complex with that in some situations though, for example some objects I might want to copy, while others I might just want to reference.
If I am making a threejs project and I want to shallow copy of a mesh object then I just need to use the clone method of a mesh instance. Once I have a shallow copy it is then a question of what additional steps I might want to take when it comes to cloning additional nested objects of the mesh object. This will then be a post on the mesh clone method, and while I am at it also address some of the issues that might come up when making copies of mesh objects, and cloning objects in general.
Mesh objects are just one example of a kind of object that is based off of the object3d class. With that said there is not just making a copy of a mesh object, but also getting into how to go about making copies of object3d based objects in general. There is also a lot to be aware of when it comes to object3d based objects such as the fact that they can have one or more children. Also there are a lot of methods in the class that can prove to be useful when addressing things that happen when cloning objects. For example there is the traverse method that is a good way to loop over not just the children of an object, but the children of children, and the object itself and apply custom logic that is used to clone or reference materials and geometry as needed.
The source code examples that I am writing about in this post can be found on Github in my test threejs repository. This repo is also where I park the source code examples that I write about in my many other blog posts on threejs as well.
When I first write this post I was using version r111 of threejs, and the last time I edited this post I was using r146 when I came around to doing a little editing. I can not say much has changed with the mesh clone method at least between these two versions, however a lot has changed to many other threejs features, and these changes can often result in code breaking. always be mindful of the version of threejs that you are using, and the version that was used when a code example was authored and published to the web.
To start out this post I will be going over a number of basic getting started type examples of the clone method of the mesh class. Just simply calling the clone method of a mesh object is simple enough. Also if I am in a situaiton in which all the clones that I make can share the same material and geometry, then that will also often be the end of it as well. However often I might want to make clones of some of the nested objects as well, so I should have a few examples in this seciton on that topic as well.
To copy a mesh in threejs all I need to do is just call the clone method of a mesh object instance, and what will be returned is a copy of that mesh. It is just important to know what a copy of a mesh object is and what it is not. The resulting copy is a copy of things like the position and rotation of the mesh, but not the state of the geometry that it is using, or whatever might be going on with the materials that are being used.
Here I have a simple example where I am creating an original mesh with the THREE.Mesh constructor, and then creating a bunch of copies with the clone method of that Mesh instance.
This results in a bunch of mesh objects placed around the original mesh object, I am also having each of the new mesh objects face the position of the original mesh object. So each copy can have its own position, and rotation, but they still share the same reference to the same objects when it comes to geometry and materials.
1.2 - Mesh copy will not copy the material used, so changes to the original material will effect the clones.
When copying a Mesh it is the Mesh that will be copied, but not the material that the mesh is using. This is what I would expect to happen, but never the less I should write a quick section about this. If I take the above simple example of the mesh clone method and make use of the standard material rather than the normal material I can set a color value for the material when it comes to making the original. When I go to make clones of the original mesh properties that have to do with the mesh itself will of course be copied, so I can give new positions and rotations for example that will not effect the original and bis versa. However if I make a change to the material that will effect all mesh object as that is not being cloned.
So when I change the color of the material used in the original mesh to green from red, that will result in all the mesh objects that are cloned from that mesh to change to green. If this is a desired effect then there is no problem, if it is not a desired effect then there are a number of ways to address this. One way would be to just drop the use of the mesh clone method and just make new Mesh objects along with geometries all together. However for this example I made use of the clone method of the material base class to create and return a new material to one of the copies of the original mesh which also has a desired outcome when it comes to this sort of thing.
The clone method of a mesh will just clone the mesh object and not the material, or the geometry. So just like with the material used by all clones, any change to the geometry of the original or any clone will also effect all copies. For example if I again have a situation in which I make a whole bunch of copies from an original mesh object, and then do something like change the material index values of the geometry used by the original that in turn will effect all the copies also.
Using the clone method might be the way that I would want to go about creating a whole much of copies of some kind of main mesh object because doing so results in just copying the mesh and the children of the mesh. This results in a more efficient way of creating a whole bunch of mesh objects that all share the same geometry and materials. Often it might just be mesh objects level property values that I will want to change up a little here and there, so this kind of approach will not result in a problem. However in some cases I will want each mesh to have its own geometry and material values. So when it comes to this kind of situation I often just drop the use of the mesh clone method all together and just create stand alone mesh objects one at a time, as well as stand alone geometry, and material objects for each mesh.
So the idea here then is that in place of calling the clone method of a mesh there is just working out some logic that has to do with just calling THREE.Mesh to begin with. When it comes to passing the geometry and materials to use I can then create a new geometry and material each time. One simple way to do this is to just have a simple helper function that when called will do just this.
So for this demo each time I call the createBox helper it will create a new mesh, and with it also a new geometry and material as well.
Although the first demo works well when it comes to always having a whole new mesh with geometry and materials there is also having some options in which I can pass the geometry and material that I want to use. Also while I am at it there is having options that can be set to true or false if I want the objects to all share the given geometry and or material or not.
One thing about the mesh clone method is that it will clone the mesh objects of the children, but it will just clone the mesh objects themselves and not any other additional nested objects such as the material and geometry. So in this section I will be writing about a few source code examples that have to do with this specific topic.
For this example I am creating a mesh object, and then I am also creating a whole bunch of children for that mesh object as well while I am at it. I then make a number of clones of the main parent mesh object. When doing so it will clone the parent mesh object, and it will also create clones of each child as well. This means that if I mutate an object3d class property such as say the y position of a child that will just effect that one child, and not any source object. However if I do not also make clones of the materials if I change something with the material that will effect the source child as well.
So then if I want to change not just object3d and mesh properties, but also material and geometry data of a child that was cloned from a source object, then I will also want to clone thous additional objects. So after making a clone of a source parent object, I might want to use the object3d traverse method to loop over all mesh objects and create clones for that materials, geometry, and any additional nested objects that might come up as well.
So then the Mesh clone method will indeed clone a mesh object, and also any children it might have. However that is it, the method will not deep clone everything when it comes to what might be going on with the geometry and material. When I get some more time to work on this one I think I could stand to work out a few more examples on this topic. There is what the Mesh clone method does, and there is what the Mesh clone method does not do.