更改克隆对象的属性会更改所有对象

问题描述 投票:0回答:1

我已经加载了一个 OBJ 文件,并从原始文件中将其

.clone()
放入数组中。后来我想将其中一些的
vertexColor
更改为不同的颜色,但是更改一个会改变所有的颜色。

var oload = new OBJLoader();
oload.load("objects/tunnel1.obj", function(data)
{
    tunnels[0] = data;
    tunnels[0].traverse(function(titem)
    {
        if(titem.isMesh)
        {
            if(titem.name.toUpperCase().indexOf("INNER")>-1)
            {
                titem.material = new THREE.MeshBasicMaterial(map: wnewtex, vertexColors: true);
            }
        }
    });
});

for(var x = 0; x < width; x++)
{
    for(var y = 0; y < height; y++)
    {
        if(leveldata[x][y] == 15)
        {
            tunnels.push(tunnels[0].clone());
            tunnels[tunnels.length-1].position.set(-x*2,newh,(height-y-1)*2);
            scene.add(tunnels[tunnels.length-1]);
        }
        else if(leveldata[x][y] == 16)
        {
            tunnels.push(tunnels[0].clone());
            tunnels[tunnels.length-1].position.set(-x*2,newh,(height-y-1)*2);
            tunnels[tunnels.length-1].rotation.set(0,Math.PI/2,0);
            scene.add(tunnels[tunnels.length-1]);
        }
        else if(leveldata[x][y] == 23)
        {
            tunnels.push(tunnels[0].clone());
            tunnels[tunnels.length-1].position.set(-x*2,newh,(height-y-1)*2);
            tunnels[tunnels.length-1].rotation.set(0,Math.PI/2,0);
            tunnels[tunnels.length-1].traverse(function(titem)
            {
                if(titem.isMesh)
                {
                    if(titem.name.toUpperCase().indexOf("INNER")>-1)
                    {
                        titem.geometry.setAttribute("color",new THREE.BufferAttribute(new Float32Array(item.geometry.attributes.position.count*3), 3 ));
                        var colort = titem.geometry.attributes.color.array;
                        for(var v2 = 0; v2 < titem.geometry.attributes.position.count*3; v2+=3)
                        {   // Make Red
                            colort[v2+0] = 1;
                            colort[v2+1] = 0;
                            colort[v2+2] = 0;
                        }
                        titem.geometry.attributes.color.needsUpdate = true;
                    }
                }
            });
            scene.add(tunnels[tunnels.length-1]);
        }
        else if(leveldata[x][y] == 26)
        {
            tunnels.push(tunnels[0].clone());
            tunnels[tunnels.length-1].position.set(-x*2,newh,(height-y-1)*2);
            tunnels[tunnels.length-1].rotation.set(0,Math.PI/2,0);
            tunnels[tunnels.length-1].traverse(function(titem)
            {
                if(titem.isMesh)
                {
                    if(titem.name.toUpperCase().indexOf("INNER")>-1)
                    {
                        titem.geometry.setAttribute("color",new THREE.BufferAttribute(new Float32Array(item.geometry.attributes.position.count*3), 3 ));
                        var colort = titem.geometry.attributes.color.array;
                        for(var v2 = 0; v2 < titem.geometry.attributes.position.count*3; v2+=3)
                        {   // Make Green
                            colort[v2+0] = 0;
                            colort[v2+1] = 1;
                            colort[v2+2] = 0;
                        }
                        titem.geometry.attributes.color.needsUpdate = true;
                    }   // If 26 was the last tunnel adjusted
                }       // then even 23 turns green
            });
            scene.add(tunnels[tunnels.length-1]);
        }
    }
}

我认为

.clone()
不会为新对象创建属性的新副本。在属性未链接的情况下制作克隆的另一种方法是什么?

javascript three.js clone
1个回答
0
投票

你是对的,

clone
维护参考,而不是制作副本。并且
clone
调用对象的
copy
函数,因此即使
Mesh.copy
也保留对原始
geometry
material
的引用,而不是制作副本。这样做是为了提高内存效率。

参考:https://github.com/mrdoob/third.js/blob/a2e9ee8204b67f9dca79f48cf620a34a05aa8126/src/objects/Mesh.js#L68(三.js r164)

但这还不是结束。您始终可以通过在执行

geometry
后取消引用
material
和/或
clone
来解决这个问题。如果你再降低一步,
clone
实际上就能达到你想要的效果。

const original = new Mesh( geo, mat )
const theClone = original.clone()

console.log( original.geometry === theClone.geometry ) // true
console.log( original.material === theClone.material ) // true

theClone.geometry = theClone.geometry.clone()
theClone.material = theClone.material.clone()

console.log( original.geometry === theClone.geometry ) // false
console.log( original.material === theClone.material ) // false
© www.soinside.com 2019 - 2024. All rights reserved.