I'm loading models using the collada loader. The loader returns an Object3D, "dae", with many child meshes. I'd like to instantiate the parent "dae" object many times without duplicating the meshes. Can I just use dae.clone()?
Put another way: I'd like to make shallow copies that all have their own transformation matrix but share the same geometry. What's the most efficient way to do this?
By default Object3D.clone()
does create a deep copy. Let's take a look at the source
clone: function ( object, recursive ) {
if ( object === undefined ) object = new THREE.Object3D();
if ( recursive === undefined ) recursive = true;
object.name = this.name;
object.up.copy( this.up );
object.position.copy( this.position );
object.quaternion.copy( this.quaternion );
object.scale.copy( this.scale );
object.renderDepth = this.renderDepth;
object.rotationAutoUpdate = this.rotationAutoUpdate;
object.matrix.copy( this.matrix );
object.matrixWorld.copy( this.matrixWorld );
object.matrixAutoUpdate = this.matrixAutoUpdate;
object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;
object.visible = this.visible;
object.castShadow = this.castShadow;
object.receiveShadow = this.receiveShadow;
object.frustumCulled = this.frustumCulled;
object.userData = JSON.parse( JSON.stringify( this.userData ) );
if ( recursive === true ) {
for ( var i = 0; i < this.children.length; i ++ ) {
var child = this.children[ i ];
object.add( child.clone() );
}
}
return object;
}
As we can see the clone
function accepts two optional arguments:
Object3D
into.So yes it is possible to make shallow copies with respect to the Object3D.children
, but that's not what you want (based on your comment).
I believe you can actually use the default behavior of Object3D.clone()
to get what you are after. Mesh.clone()
does not clone the Geometry
and Material
properties.
THREE.Mesh.prototype.clone = function ( object ) {
if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );
THREE.Object3D.prototype.clone.call( this, object );
return object;
};
Here is a couple of function I use to clone object's materials deeply. You could modify this to your needs
Also consider this information : https://github.com/mrdoob/three.js/issues/5754
/** Gives the aptitude for an object3D to clone recursively with its material cloned (normal clone does not clone material)*/
THREE.Object3D.prototype.GdeepCloneMaterials = function() {
var object = this.clone( new THREE.Object3D(), false );
for ( var i = 0; i < this.children.length; i++ ) {
var child = this.children[ i ];
if ( child.GdeepCloneMaterials ) {
object.add( child.GdeepCloneMaterials() );
} else {
object.add( child.clone() );
}
}
return object;
};
THREE.Mesh.prototype.GdeepCloneMaterials = function( object, recursive ) {
if ( object === undefined ) {
object = new THREE.Mesh( this.geometry, this.material.clone() );
}
THREE.Object3D.prototype.GdeepCloneMaterials.call( this, object, recursive );
return object;
};
You can refer to the copy
and clone
methods in Object3D
to deep clone mesh materials.
First,extends two new methods in THREE:
THREE.Object3D.prototype.deepClone = function ( recursive ) {
return new this.constructor().deepCopy( this, recursive );
},
THREE.Object3D.prototype.deepCopy = function( source, recursive ) {
if ( recursive === undefined ) recursive = true;
this.name = source.name;
this.up.copy( source.up );
this.position.copy( source.position );
this.quaternion.copy( source.quaternion );
this.scale.copy( source.scale );
this.matrix.copy( source.matrix );
this.matrixWorld.copy( source.matrixWorld );
if(source.material){
//changed
this.material = source.material.clone()
}
if(source.geometry){
//changed
this.geometry = source.geometry.clone()
}
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
this.layers.mask = source.layers.mask;
this.visible = source.visible;
this.castShadow = source.castShadow;
this.receiveShadow = source.receiveShadow;
this.frustumCulled = source.frustumCulled;
this.renderOrder = source.renderOrder;
this.userData = JSON.parse( JSON.stringify( source.userData ) );
if ( recursive === true ) {
for ( var i = 0; i < source.children.length; i ++ ) {
var child = source.children[ i ];
this.add( child.deepClone() ); //changed
}
}
return this;
}
Second,when you want to deep clone a Object3D or Scene named originalObj
.just do var newObj = originalObj.deepClone()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With