0

Lately I've been working with ThreeJS models. I managed to implement a custom function which loads each needed .obj once, and if there are more objects using the same model, clone them instead of loading them again.

The issue is that I need to animate each of the cloned meshes in a specific way.

I created an array of objects, containing a function for each of the meshes that needs to be animated which will be looped and executed when needed. The issue is that only the first model is actually being animated for some reason.

Here's the code I use for animating the meshes.

function loadModel(m){
    for(var i = 0; i<objects.length; i++){
        if(m.name === objects[i].modelData.model){
            mesh = m.mesh.clone();
            mesh.position.x = objects[i].positionX * distanceAmplifier;
            mesh.position.y = objects[i].positionY * distanceAmplifier;
            mesh.position.z = objects[i].positionZ * distanceAmplifier;
            mesh.scale.set(1000,1000,1000);
            //Adding animation
            animations.push(function(){
                mesh.rotation.z +=  1.0005;
            });
            scene.add(mesh);
        }
    }
}

While in the animation I do this:

if(animations.length === objects.length){
        animations.map(function(anim){
            anim();
        });
}

If I load different obj meshes, the first instance of each of them is being animated,but not the clone itself.

I hope somebody who had the same issue could give me a hand in sorting this out

WestLangley
  • 102,557
  • 10
  • 276
  • 276
Rotar Paul
  • 129
  • 2
  • 13

1 Answers1

1

Looks like a scope problem to me. I think it's not the first instance of your clones that is being animated, but rather the last

Examine your code here:

animations.push(function(){
    mesh.rotation.z +=  1.0005;
});

What you're doing is pushing an anonymous function into the array. But the function isn't executed immediately when it's pushed, it's just sitting around waiting to be called. When it finally is executed, mesh has long since moved on from being whatever it was when you pushed the function into the array. Since you're declaring the mesh variable somewhere outside of the scope of your loop, every single one of your references to mesh are pointing to the exact same variable.

There are two ways to solve this. An easy way would be to create a new mesh variable for every iteration of your loop instead of needlessly referencing a variable that's outside of your current scope:

var newMesh = m.mesh.clone(); // declare a brand new var instead of reusing 'mesh'
...
animations.push(function(){
    newMesh.rotation.z +=  1.0005;
});

If you had some kind of crazy reason for actually using mesh inside the scope of your loop, you could "close over" its value at the time of executing the for loop, instead of letting it be put off for later. This is called a "closure" and is and important thing to understand in JavaScript:

// Create an anonymous function and pass it 'mesh'
// Then execute it immediately to capture the current 'mesh' value
(function(_mesh){
    animations.push(function(){
        _mesh.rotation.z +=  1.0005;
    });
})(mesh);

Note how now the anonymous function is not only created but it's executed immediately, and passed the mesh variable to capture it's value at the same time.

(function(){console.log("Hello.");})(); // this is executed immediately!

This has a name: "immediately invoked function expression". It's exactly what it sounds like - declare a function and then execute it immediately. It's a common way of creating a closure.

I suggest you do some reading on how scope and closures work in JavaScript:

What is the scope of variables in JavaScript?

How do JavaScript closures work?

Good luck!

Community
  • 1
  • 1
jered
  • 11,220
  • 2
  • 23
  • 34
  • Creating a new variable for each of the clones was not my best bet to go for, I've used the closure in order to make it work. I got confused that the function might be executed right when it was pushed in the array. Anyway.. using the closure worked like a charm. – Rotar Paul Mar 09 '16 at 20:44