GLTFLoader loading multiple models in a "for" loop - referencing problem

Hi experts,

I’m loading models in a for loop and although the models are loaded (and the 3D models is correct, they are different) the position and name is always set by the last entry of the for loop, meaning (in my case) all three objects have same name and position (see screenshot below). It seems the reference to the variable is kept but I don’t know why.

Code looks like this:

 for (i = 0; i < resourceData.length; i++) {
  		var loader = new THREE.GLTFLoader();
  		var oResource = resourceData[i];
  		var sModelName = "resources/" + oResource.model3D + ".gltf";
  		loader.load(sModelName, function (gltf) {
  			gltf.scene.traverse(function (node) {
  				if (node instanceof THREE.Mesh) {
  					node.castShadow = true;
  				}
  			});
  			gltf.scene.name = oResource.model3D + "-" +oResource.tagID;
  			gltf.scene.position.x = parseFloat(oResource.x);
  			gltf.scene.position.y = parseFloat(oResource.y);
  			gltf.scene.position.z = parseFloat(oResource.z);
  			scene.add(gltf.scene);
  		}, undefined, function (error) {
  			console.error(error);
  		});
  	};

I have no idea where to look at. I have a similar for loop in another context and it works just fine.
oResource looks like this:

Hi!
Wouldn’t it be better to move the loader variable out of the loop and use let instead of var inside the loop?

var loader = new THREE.GLTFLoader();
for (let i = 0; i < resourceData.length; i++) {
    let oResource = resourceData[i];
    let sModelName = "resources/" + oResource.model3D + ".gltf";
    loader.load( sModeName, function (gltf) {
        // the same code as in your original post
    }, undefined, function (error) {
        console.error(error);
    })
}

I think @prisoner849 provides a solution (except of the redundant creation of a loader in each iteration).

loader.load() takes a callback which will be executed after the file has been loaded. The problem is that var is function-scoped. Thus, the variables will be modified in every loop iteration until the last, before any files are done loading, and the values will all be the last ones. let, on the other hand, is locally scoped, that is to the end of the loop iteration. So with let, each callback will have their own corresponding settings.

I think it’s a pretty cool bug. :wink:

2 Likes

@EliasHasle Thanks for pointing :smile:

A minor simplification tip is to repalce

for (let i = 0; i < resourceData.length; i++) {
    let oResource = resourceData[i];

with

for (let oResource of resourceData) {
4 Likes

@EliasHasle @prisoner849
Gentlemen, thank you indeed for your help - I’m learning every day! Especially about the scoping of var and let! Now it works like a charm! And I also simplified the code as suggested! :blush:

2 Likes

Old thread i know, but just incasr a lonely traveller hits it. I came across this which may be of help https://redstapler.co/load-multiple-model-three-js-promise/

2 Likes