Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will three.js Object3D.clone() create a deep copy of the geometry?

Tags:

three.js

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?

like image 926
BuschnicK Avatar asked Mar 12 '14 18:03

BuschnicK


3 Answers

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:

  1. the object to clone the Object3D into.
  2. a flag to indicate whether or not to recursively clone the children.

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;

};
like image 103
Jonathan Dixon Avatar answered Dec 07 '22 23:12

Jonathan Dixon


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;
    };
like image 42
StackHola Avatar answered Dec 07 '22 22:12

StackHola


You can refer to the copyand 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()

like image 30
Anoman.M Avatar answered Dec 08 '22 00:12

Anoman.M