【Question】About load multiple models in scene

Hi!
I got this question about a long time ago.
Sometimes i need load several models into my scene.
Sometimes they got animations,which may requires all the models are fully loaded.
But since GLTFLoader load models asynchronously.
I got check if all models loaded fully.
So what my solution now is by using setTimeout method recursively check the status every 100ms or 1000ms based on the perfomance.
Something like this

  let m1,m2
  const loader = new GLTFLoader()
  loader.load('url1',gltf=>{
   m1 = gltf.scene
  })

  loader.load('url2',gltf=>{
    m2 = gltf.scene
  })

   check()

  function check(){
    if(m1!==undefined&&m2!==undefined){
        // do something
    }else{
       setTimeout(check(),1000)
    }
  }

Or i can load all models in threejs editor ,Blender or someting else,then export them as one and load them as one.
But i dont know if there are a better way to synchronize them ?
In common practice whats the best way to synchronize them?

I think you are looking for LoadingManager.

2 Likes

I think this class wont do it,I wanna sychronize them,So they can load as one,not scattering individuals

I think LoadingManager could suit your need, but if you don’t want to use it maybe you could put all your assets in one gltf file and sort them by name once it’s loaded ?

Try my loading manager for textures, models, sounds.

<!DOCTYPE HTML>
<html>
<head>
<style>
</style>
</head>


<body style="margin:0px;">
<div id="project" style="font-family:tahoma;">
<div id="loading" style="position:absolute;display:block;top:50%;width:100%;text-align:center;font-family:arial;font-size:40px;color:#ffffff;text-shadow:1px 1px 4px #393342;">LOADED <span id="loading_amount"></span></div>
<div id="begin" onclick="this.style.display='none';stop=0;loop();" style="cursor:pointer;position:absolute;display:none;top:50%;width:100%;text-align:center;font-family:arial;font-size:40px;color:#ffffff;text-shadow:1px 1px 4px #393342;">START</div>
<canvas id="canvas" width="800" height="600" style="vertical-align:top;"></canvas>
</div>
</body>


<script type="text/javascript" src="https://threejs.org/build/three.js"></script>
<script type="text/javascript" src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>


<script type="text/javascript">


"use strict"


// ____________________ TEXTURE AND MODEL LOADER ____________________


var loader_textures_show = 1; // 0 - DO NOT DISPLAY THE LIST OF TEXTURES IN THE CONSOLE, 1 - DISPLAY
var loader_models_show = 1; // 0 - DO NOT DISPLAY THE LIST OF MODELS IN THE CONSOLE, 1 - DISPLAY
var loader_sounds_show = 1; // 0 - DO NOT DISPLAY THE SOUND LIST IN THE CONSOLE, 1 - DISPLAY


var loader_total = 0; // HOW MUCH TO DOWNLOAD
var loader_loaded = 0; // HOW MUCH DOWNLOADED
var loader_textures_loaded = 0; // HOW MUCH TEXTURES DOWNLOADED
var loader_models_loaded = 0; // HOW MANY MODELS DOWNLOADED
var loader_sounds_loaded = 0; // HOW MANY SOUNDS LOADED


// ____________________ DOWNLOAD MANAGER ____________________


var loadingManager = new THREE.LoadingManager ();


// ____________________ DOWNLOAD COUNTER ____________________


loadingManager.onProgress=function(item,loaded,total){


var found=0;


if(item.match(/(\.jpe?g($|\?)|\.png($|\?)|\.gif($|\?)|\.bmp($|\?)|\.dds($|\?))/gi)){
found=1;
loader_textures_loaded++;
if(loader_textures_show){ console.log("%c"+item,"font-weight:bold;color:#004090"); }
}


if(item.match(/(\.obj($|\?)|\.fbx($|\?)|\.gltf($|\?)|\.glb($|\?)|\.bin($|\?))/gi)){
found=1;
loader_models_loaded++;
if(loader_models_show){ console.log("%c"+item,"font-weight:bold;color:#448A44"); }
}


if(item.match(/(\.ogg($|\?)|\.mp3($|\?)|\.wav($|\?))/gi)){
found=1;
loader_sounds_loaded++;
if(loader_sounds_show){ console.log("%c"+item,"font-weight:bold;color:#A73CEE"); }
}


if(found==0){ console.log("%c ADD FORMAT FOR THIS FILE: "+item+" ","background:#ff0000;color:#ffffff"); return; }


loader_loaded++;
loader_total=total;


};


// ____________________ RUN CHECK FILES UPLOAD WHEN THE PAGE IS FULLY LOADED ____________________


window.onload=function(){ loader_check(); }


// ____________________ CHECK UPLOADED FILES ____________________


function loader_check(){


document.getElementById("loading_amount").innerHTML=loader_loaded+"/"+loader_total;


if(loader_total==loader_loaded){
document.getElementById("loading").style.display="none";
console.log("%c TEXTURES: "+loader_textures_loaded+" ","background:#222;font-weight:bold;color:#bada55");
console.log("%c MODELS: "+loader_models_loaded+" ","background:#222;font-weight:bold;color:#bada55");
console.log("%c SOUNDS: "+loader_sounds_loaded+" ","background:#222;font-weight:bold;color:#bada55");
console.log("%c --> ALL LOADED <-- ","background:#222;font-weight:bold;color:#bada55;");
init();
return;
}


requestAnimationFrame(loader_check);


}


// ____________________ AFTER DOWNLOAD FIRST INITIALIZATION ____________________


function init(){


document.getElementById("begin").style.display="block";


}


</script>


<script type="text/javascript">


"use strict"


//____________________ SOUNDS LOADER ____________________


var sounds_list=[
//["NAME,"PATH"],


["music","https://threejs.org/examples/sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg"],


];


var sound=[];
window.AudioContext=window.AudioContext || window.webkitAudioContext;
var soundCtx=new AudioContext();
var soundCtx_destination=soundCtx.destination;
var audioLoader=new THREE.AudioLoader(loadingManager);


var max=sounds_list.length;


for(var n=0;n<max;n++){
var name=sounds_list[n][0];
audioLoader.load(sounds_list[n][1],function(buffer){ sound[name]=buffer; });
}


function sound_play_once(name){
var data=soundCtx.createBufferSource();
data.buffer=sound[name];
data.connect(soundCtx_destination);
data.start();
}


</script>


<script type="text/javascript">


"use strict"


var canvas_width=1024;
var canvas_height=768;
var canvas_half_width=canvas_width/2;
var canvas_half_height=canvas_height/2;


var mesh=[];
var tex=[];


const texture_loader=new THREE.TextureLoader(loadingManager);
const GLTFLoader=new THREE.GLTFLoader(loadingManager);


var renderer_PixelRatio=window.devicePixelRatio;


var renderer=new THREE.WebGLRenderer({canvas:canvas,antialias:true,alpha:true,transparent:true,premultipliedAlpha:false,physicallyCorrectLights:false,logarithmicDepthBuffer:false});
renderer.setSize(canvas_width,canvas_height);
renderer.setPixelRatio(renderer_PixelRatio);
renderer.autoClear=false;
renderer.shadowMap.enabled=true;
renderer.shadowMap.type=THREE.VSMShadowMap


var scene=new THREE.Scene();


var camera=new THREE.PerspectiveCamera(60,canvas_width/canvas_height,0.05,10000);
camera.position.set(0,0,5);


//____________________ TEXTURES ____________________


var maxanisotropy=renderer.capabilities.getMaxAnisotropy();


tex["wall"]=texture_loader.load("https://threejs.org/examples/textures/patterns/circuit_pattern.png");
tex["cell"]=texture_loader.load("https://threejs.org/examples/textures/crate.gif");


//____________________ MODELS ____________________


GLTFLoader.load('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf',gltf=>{
mesh["head"]=gltf.scene;
scene.add(mesh["head"]);
})


function loop(){
requestAnimationFrame(loop);
renderer.render(scene,camera);
}


</script>


</body>
</html>

1 Like

Without telling you exactly how to solve this, since it is really trivial… Read up on Promises and the use of async and await in Javascript. The gltf loader has a loadAsync method that you can use.

If you want to load everything in one go and know exactly when everything is finished, then Promise.all() is your best friend :wink:

3 Likes

settimeout and polling, there really is no reason for that. like @Harold said, promises.

async function app() {
  const loader = new GLTFLoader()
  const [m1, m2] = await Promise.all([
    loader.loadAsync(url1),
    loader.loadAsync(url2),
  ])
  //m1.scene. ...
  //m2.animations. ...

edit, oops, i skipped the part where you were supposed to figure this out by yourself - sorry for spoiling your fun :-/

2 Likes

So basically you run loader_check method every frame till they all loaded ?

Chaser got a solution with LoadingManager,He update the loaded content count and run check method every frame

Thats really great!Thanks

Much appreciate!