# async/await/loadAsync - black magic for me :-(

**URL:** <https://discourse.threejs.org/t/async-await-loadasync-black-magic-for-me/54595>\
**Category:** Questions\
**Tags:** group, obj-loader, async\
**Created:** [August 3, 2023, 9:23am UTC](https://discourse.threejs.org/t/async-await-loadasync-black-magic-for-me/54595 "2023-08-03T09:23:24Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![three3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/three3d/32/38430_2.png) [@three3d](https://discourse.threejs.org/u/three3d)\
**Post date:** [August 4, 2023, 11:22pm UTC](https://discourse.threejs.org/t/async-await-loadasync-black-magic-for-me/54595/3 "2023-08-04T23:22:22Z")

</div>

After a lot of ups and downs :), rearranging the code like lego blocks, I finally managed to somehow implement async/await…

This code example looks interesting but turned out to be too difficult for me to implement 😟:  
…  
const [font, hdri, gltf] = await Promise.all([  
new Promise((res, rej) =\> fontLoader.load(“/font.json”, res, rej)),  
new Promise((res, rej) =\> rgbeLoader.load(“/warehouse.hdr”, res, rej)),  
new Promise((res, rej) =\> gltfLoader.load(“/model.glb”, res, rej)),  
])  
[\> more…](https://discourse.threejs.org/t/ghaaaa-why-does-this-produce-an-error/53586/11)

However, these examples have become the most inspiring for me:  
[1 \> more…](https://discourse.threejs.org/t/wait-for-object-loader/30573/4)  
[2 \> more…](https://discourse.threejs.org/t/wait-for-object-loader/30573/7)

The hardest part for me was separating the objLoader and mtlLoader sequences into separate lines of code:

```
import * as THREE from 'three';

import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';	
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let camera, controls, scene, renderer, dirLight;

let AllModelGroup; // group of all loaded models

async function init() {

			scene = new THREE.Scene();
			scene.background = new THREE.Color( '#ffffff' );

			renderer = new THREE.WebGLRenderer( { antialias: true } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
			camera.position.set( -30, 50, 70 );

			// controls
			controls = new OrbitControls( camera, renderer.domElement );
				controls.minDistance = 1;
				controls.maxDistance = 100;
				controls.target.set(15,10,0);	// camera target	

			// lights
			dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
			dirLight.position.set(0, 50, 50);
				dirLight.castShadow = true;
				camera.add( dirLight );
				scene.add( camera );
				
			const ambientLight = new THREE.AmbientLight( 0xffffff, 1 );
			scene.add( ambientLight );

		await initModel();
		await dispGroup();	// show structure of groups loaded *.obj

	
			window.addEventListener( 'resize', onWindowResize );
}

function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
	requestAnimationFrame( animate );
	controls.update();
	render();

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

init();
animate();

async function initModel () {

	// list of *.obj models to load	
	let mod2load=['box1', 'box2', 'box3']; 

	const mtlLoader = new MTLLoader();
	const objLoader = new OBJLoader();

	const LoadMaterials = async (loader, fname) => {
	  return await loader.loadAsync( fname+'.mtl');
	}

	// create an empty group of all *.obj models to load 
	// and attach it to the scene
	AllModelGroup = new THREE.Group;
	AllModelGroup.name = 'AllModelGroup';
	scene.add( AllModelGroup );

for (let i = 0; i < mod2load.length; i++) {

		let fname = mod2load[i], fpath='models/';
		
		
	let MyObjGroup = await new THREE.Group; // the main group of one loaded model *.obj
	let MyLineGroup = await new THREE.Group;	// subgroup of hybrid edges
	let MyAllLineGroup = await new THREE.Group;	// subgroup of all edges

	await mtlLoader.setPath( fpath );
	const materials = await LoadMaterials(mtlLoader, fname);
 
		await materials.preload();

		objLoader.setMaterials( materials );
		objLoader.setPath( fpath );
		let mod3one = await objLoader.loadAsync(fname+'.obj');

		// based on the loaded model *.obj, among others generate its edges
		await mod3one.traverse(await function(node) {			

				if ( node.isMesh && node.material) {
					node.material.side = THREE.DoubleSide;
						let edges = new THREE.EdgesGeometry(node.geometry);
						let line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial( { color: '#000000' } ) );
					// assume the edges of the yellow model as hybrid, 
					// requiring showing together with the body of the model
					// and join them to MyLineGroup
					if (node.material.name =='yellow' ) {
						MyLineGroup.add( line );
					}else{
					// edges of other materials join MyAllLineGroup, 
					// which is hidden by default
						MyAllLineGroup.add( line );
					}
				}
			}); // mod3one.traverse ------------------------------

	// correct/complete data in sub/groups
	MyObjGroup.name="MyObjGroup";
	mod3one.name="ObjBody";		
	MyLineGroup.name="MyLineGroup";
	MyAllLineGroup.name="MyAllLineGroup";

	// remember the name of the file in the group
	MyObjGroup.fname=fname;
	mod3one.fname=fname;		
	MyLineGroup.fname=fname;		
	MyAllLineGroup.fname=fname;	
	
	// when the scene is loaded for the first time, hide the group of all edges
	MyAllLineGroup.visible=false;

	MyObjGroup.add( mod3one );
	MyObjGroup.add( MyLineGroup );
	MyObjGroup.add( MyAllLineGroup );

	// append the group of the currently loaded model to the group of all models
	AllModelGroup.add( MyObjGroup );

	// in the console, show the groups of the currently loaded model *.obj
	// console.log(fname);		
	// console.log(MyObjGroup);
	// console.log(MyLineGroup);
	// console.log(MyAllLineGroup);

// go to load next model *.obj
}//for

} // initModel

async function dispGroup () {	// show structure of groups loaded *.obj

	let x,y,z,q;

	console.log(' ------ scene --------');	// OK
	console.log(scene);	// OK

	console.log(' ------ AllModelGroup --------');	// OK
	x= scene.getObjectByName( "AllModelGroup" );
	console.log(x);

	for (let i = 0; i < x.children.length; i++) {
		
		console.log("=== "+x.children[i].fname+" ===");
		y=x.children[i];//getObjectByName( "MyObjGroup" );
			console.log( y.fname +" "+y.name );
		z=y.children;

		if (typeof z=='object' && z.length > 0 ){
			for (let chil of z) {
				console.log( chil.fname +" - "+chil.name );
				// console.log( chil );				
			} // podgrupy AllModelGroup
		}
	} // for
} // dispGroup

```

I think I have achieved my intended goal:

- ordered obj models are loaded in the ordered order
- loaded obj models are placed in groups in the same order
- and it seems that the results are immediately available to be checked in the console - without any delay

 ![conslog](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/8/8/884235d6cb235bf2be817bb9e861587634267780.png)

Remaining issues to be resolved (someone help me ?):

1. Can this current code be syntactically improved ?
2. Is there too much **await** in it?
3. Do I have to have the function **LoadMaterials** separately ?
4. Can all this be achieved with the previous one  
arrangement of nested **objLoader** and **mtlLoader**?  
Then I had a **loading progress bar** in JS syntax:

Previous syntax:

```
let mtlLoader = new MTLLoader();
mtlLoader.setPath( fpath );
mtlLoader.load( fname+'.mtl', function ( materials ) {
	materials.preload();
	
	let objLoader = new OBJLoader();
	objLoader.setMaterials( materials );
	objLoader.setPath( fpath );
	objLoader.setPath( fpath );
	objLoader.load( fname+'.obj', function ( mod3one ) {
		...
	},
	onProgress	//where to move this function ?
	);
});

```

Previously, instead of grouping loaded \*.obj models, I used layers to store \*.obj models. But in addition, I stored the edges of the models on two more layers. Therefore, each loaded \*.obj occupied 3 layers. With this method, I could load a maximum of 10 \*.obj models into the scene.  
After switching to grouping of loaded objects, I got rid of these limitations and at the same time developed the existing \*.obj model control properties on the stage:

- controlling the visibility of individual models;
- controlling the model display mode (with or without edges, etc.);

 ![modelonoff](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/8/483ef74bbb599d961384be44ad23a95a03943cde.jpeg)  
 ![modeloffedges](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/8/4814e5b7359edc68af825ce963e23b0a7c2bfc70.jpeg)  
 ![modeledges](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/5/154d3f77e8f420c05ca3fd19581679457e751671.jpeg)

I have been satisfied for a month of learning about ThreeJs. 😀  
ThreeJs in conjunction with LightGallery promises to be a great tool for publishing architectural and construction models (exported from ArchiCAD to \*.obj) for the purpose of e.g. **quick** workshop communication with other designers and construction contractors.

---

_[View the full topic](https://discourse.threejs.org/t/async-await-loadasync-black-magic-for-me/54595)._
