three.js Object3D.clone()会创建几何的深层副本吗?

时间:2014-03-12 18:41:20

标签: three.js

我使用collada loader加载模型。加载器返回一个Object3D,#34; dae",包含许多子网格物体。我想实例化父母" dae"对象多次没有重复网格。我可以使用dae.clone()吗?

换句话说:我希望制作浅色副本,这些副本都有自己的变换矩阵,但共享相同的几何体。什么是最有效的方法?

4 个答案:

答案 0 :(得分:7)

默认情况下Object3D.clone()会创建一个深层副本。我们来看看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;

}

我们可以看到clone函数接受两个可选参数:

  1. 要将Object3D克隆到的对象。
  2. 一个标志,指示是否递归克隆子项。
  3. 所以是的,可以制作关于Object3D.children的浅拷贝,但这不是你想要的(基于你的评论)。

    我相信您实际上可以使用Object3D.clone()的默认行为来获取您所追求的内容。 Mesh.clone()不会克隆GeometryMaterial属性。

    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;
    
    };
    

答案 1 :(得分:2)

这里有一些我用来深入克隆对象材料的函数。您可以根据需要对其进行修改

另请考虑以下信息: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;
    };

答案 2 :(得分:1)

three.js Object3D.clone()创建几何和材质的深层副本。它将引用克隆对象的几何形状和材料。

您可以在 three.module.js 中看到它:

Mesh.prototype = ... {

    ...,

    copy: function ( source ) {
        Object3D.prototype.copy.call( this, source );

        ...

>>>>>>> this.material = source.material; <<<<<<<
>>>>>>> this.geometry = source.geometry; <<<<<<<

        return this;

    }

    ...

}

因此,关于OP的问题:是的,您可以只使用dae.clone()

对于包含几何图形和材质的深层克隆,只需更改上述{​​{1}}函数的两行即可:

Mesh.prototype.copy()

请记住,这是一个性能问题,因为three.js必须为每个object3D(包括所有网格)计算单独的几何。

答案 3 :(得分:0)

您可以参考copy中的cloneObject3D方法来深深克隆网格物体材料。

首先,在三种方法中扩展了两个新方法:

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;

    }

第二,当您想深度克隆名为originalObj的Object3D或场景时,只需执行var newObj = originalObj.deepClone()