I have loaded an OBJ file and from that original I .clone()
it into an array. Later I wish to change the vertexColor
of some of them to a different color, but changing one changes them all.
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]);
}
}
}
I take it .clone()
does not make a new copy of the attributes for the new object. What is another method to make a clone where the attributes are not linked?
You are correct that clone
maintains references, rather than making copies. And clone
calls the object's copy
function, so even Mesh.copy
keeps references to the original geometry
and material
, rather than making copies. This is done for memory efficiency.
Reference: https://github.com/mrdoob/three.js/blob/a2e9ee8204b67f9dca79f48cf620a34a05aa8126/src/objects/Mesh.js#L68 (three.js r164)
But it's not the end. You can always get around it by dereferencing the geometry
and/or material
after performing a clone
. And clone
actually does what you want if you take that single step lower.
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