【问题标题】:Will three.js Object3D.clone() create a deep copy of the geometry?three.js Object3D.clone() 会创建几何的深层副本吗?
【发布时间】:2014-04-17 03:26:21
【问题描述】:

我正在使用 collada 加载程序加载模型。加载器返回一个带有许多子网格的 Object3D,“dae”。我想多次实例化父“dae”对象而不复制网格。我可以只使用 dae.clone() 吗?

换一种说法:我想做浅拷贝,它们都有自己的变换矩阵,但共享相同的几何图形。最有效的方法是什么?

【问题讨论】:

  • 源码是公开的,为什么不看呢?或者您可以创建一两个测试并尝试一下。

标签: three.js


【解决方案1】:

默认情况下,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. 一个标志,用于指示是否递归克隆子级。

所以是的,可以对 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;

};

【讨论】:

  • 是的,我看到了那个和旗帜。但是我仍然不完全确定这是我正在寻找的答案。子对象是 Object3D。我确实想复制那些。我只是不想复制网格。网格应由所有实例共享,而对象层次结构应保持不变。
  • 克隆此时不接受任何参数(Three.js release 73)clone line here
【解决方案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;
    };

【讨论】:

  • @michael-p 你怎么用这个?用object.GdeepCloneMaterials() 替换object.clone() 永远不会调用mesh.GdeepCloneMaterials()
  • Mesh 是 Object3D 的子类,因此它会
【解决方案3】:

您可以参考Object3D中的copyclone方法对网格材质进行深度克隆。

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

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()

【讨论】:

    【解决方案4】:

    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()

    对于包含几何和材质的深度克隆,只需更改上述Mesh.prototype.copy()函数的两行:

    this.material = source.material.clone();
    this.geometry = source.geometry.clone();
    

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

    【讨论】:

      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 2012-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      • 1970-01-01
      相关资源
      最近更新 更多