Modifying characteristics of a duplicated object will affect every object

After loading an OBJ file, I created a clone of it in an array. However, when I attempt to change the vertex color of one clone, all the clones are affected. How can I create independent clones with unique attributes?

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

It appears that using .clone() does not create independent copies of the attributes for the new object. Does anyone know of an alternative method to clone objects without linking their attributes?

Answer №1

It is correct that clone maintains references instead of creating copies. When clone is called, the object's copy function is invoked, which means that even Mesh.copy retains references to the original geometry and material rather than duplicating them. This approach is chosen for the sake of memory efficiency.

For more details, please refer to: https://github.com/mrdoob/three.js/blob/a2e9ee8204b67f9dca79f48cf620a34a05aa8126/src/objects/Mesh.js#L68 (three.js r164)

However, there is a workaround available. By dereferencing the geometry and/or material after executing a clone, you can achieve the desired outcome. This can be demonstrated by taking an extra step as shown below:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with jQuery: Changes are not being triggered and clicks are also not working

I managed to recreate the modifications of my complex script in a simple jsfiddle, which can be found here. Below is the code I am working with locally: HTML <input type="text" id="rangeStart" value="updateMe" /><br/> <input type="text" c ...

programming for the final radio button text entry

I am struggling with a form that has 5 radio buttons, including an "other" option where users can manually enter text. The issue I'm facing is that the form only returns the manual entry text and not any of the preset radio values. I need it to work f ...

Is it possible to retrieve the key value of the array element that triggered a function call?

I'm looking to streamline my webpage's code by reading an XML file that contains a variable number of objects. In my JavaScript code, I create an array to store each object and loop through the XML data to generate them. As I iterate through the ...

NodeJS allows for the dynamic import of modules, enabling a flexible

I'm currently developing a CLI package within a monorepo that contains a command called buildX. This command goes through various directories, attempting to use the require function to locate a module within certain files in those directories. In ess ...

Traversing through JSON main sections, checking for operation and subsequently retrieving data

I have a json structure below: { users: [ { action: 'add', payload: [Array] } ], categories: [ { action: 'add', payload: [Array] } ], products: [ { action: 'add', payload: [Array] } ] } Can you suggest a method using .m ...

By harnessing a JSON response

After sending an ajax request, the server's response is as follows: {"error":false,"success":true} The ajax code used: $.ajax({ url: '/update', type: 'post', data: $(this).serialize(), success: function(response) ...

Showing nested arrays in API data using Angular

I would like to display the data from this API { "results": [ { "name": "Luke Skywalker", "height": "172", "mass": "77", & ...

Tips for closing two nested Material-UI popovers when a button is clicked or when clicked elsewhere

Trying to create a menu with nested popovers from Material-ui has presented a challenge. I want all the popovers to close when I click on a menu option, rather than having to close them individually. Additionally, it would be more user-friendly if the popo ...

What is the best way to prevent an HTML form from being submitted when a user is not logged in, but still allow submission when the user is signed

One of the requirements for users of my application is to be signed in before they can submit form information. Upon clicking on the submit button, my jQuery script verifies if the user is already signed in. If the user is not signed in, an error message ...

Issue with Submit Button Functionality following an Ajax Request

I am facing an issue where the submit button does not work after an ajax call, but works fine if I reload the page. The problem arises when a modal is displayed for email change confirmation. If the user confirms the change, the form submits successfully. ...

Using JQuery to append an additional column to an HTML table at the end, determined by array information

I've been experimenting with how to enhance an html table by adding a new column of data. The process involves clicking a button, extracting the existing data column in the table, storing it in an array, performing calculations on it, and then display ...

Is there a way for me to confirm whether the response includes an array?

I need to enable the icon if there is an array present in the response. How can I verify the presence of an array in the response? Here's the code snippet I attempted: export function disableActions(name, data) { case i18next.t('abcd') ...

Is there a way to set the starting position of the overflow scroll to the middle?

Is there a way to have the overflow-x scrollbar scroll position start in the middle rather than on the left side? Currently, it always begins at the left side. Here is what it looks like now: https://i.stack.imgur.com/NN5Ty.png If anyone knows of a soluti ...

What is the best way to retrieve a document from a collection in a Meteor application?

My experience with mongodb is very limited, so I need help on how to retrieve a document from a meteor collection. I am trying to check if a document exists for the user and update it with an object. if (Saves.find({_id: Meteor.userId()}).fetc ...

Change ES6 JavaScript to ES5 standard

Is there a way to transform this code snippet from other questions into ES5 format? I am attempting to extract data from a JSON array. var match = function(query, input) { return input.filter(function(entry) { return Object.entries(query).every(fun ...

Using PHP variables in JavaScript is not compatible

Currently, I am facing an issue where PHP variables inside the javascript code are not being echoed. When I try to echo the variables outside of the javascript, everything works perfectly fine. After carefully reviewing my code multiple times, I still cann ...

Create a new function within the GraphQL Resolvers file

I am trying to define a function within the same ts file as where I specify the resolvers export const resolvers = { Query: { books: () => { return [ { title: 'Harry Potter and the Chambe ...

Employing jQuery to populate information into an input field, yet encountering an issue where the data is not being successfully transmitted to

On my page, there is a form with an input box <input name="bid_price" id="bid_price" class="form-control"> If I manually enter a value, it gets posted successfully But when I try to insert a value using jQuery, it doesn't get posted, even tho ...

Using Angular's ng-repeat prefilter with JavaScript

Is it possible to achieve the functionality of this angular js filter ng-repeat on a tr element using pure javascript? Could it be done in just one custom filter? Please note that showRow is a function that returns a boolean value, and searchString is a s ...

Invalid file name detected during the download process

Below is the Javascript code I currently use to download a pdf: var link = document.createElement('a'); link.innerHTML = 'Download PDF file'; link.download = "Report.pdf"; link.href = 'data:application/octet-stream;base64 ...