Group.add() inside MTLLoader + OBJLoader?

I can’t manage to use grouping while loading the *.obj model:

let MyGroup = new THREE.Group;

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.load( fname+'.obj', function ( mod3one ) {		
		MyGroup.add( mod3one );
		// scene.add(mod3one);
	});
});
scene.add( MyGroup );

I get a message:
ReferenceError: MyGroup is not defined

Without the possibility to debug, my uneducated guess is that MyGroup is not a global variable; i.e. the code fragment above is somewhere inside a function.

If this is the case, define MyGroup where you define scene:

let scene = new THREE.Scene();
let MyGroup = new THREE.Group();
scene.add( MyGroup );

If this is not the case, ignore this message.

1 Like

Right!
It is working now.
Now I have in the scene, for example, a group name:“AllModelGroup” and in it a subgroup “MyObjGroup”.
I know how to get to AllModelGroup: scene.getObjectByName( “AllModelGroup” );
and how to get to children MyObjGroup ?
to do …group.visible=true/false;

You can use the same way:

scene.getObjectByName('MyObjectGroup')

Notes:

  • it is faster to keep this group in a variable, so you can acess it directly, instead of traversing all the scene
  • if you have time, please, read the Three.js documentation about getObjectByName, as it specifically says: “Searches through an object and its children.
1 Like

I only know the basics of JS. That’s why I reach many goals by trial and error. But I’m still very happy with the results after 3 weeks of learning three.js.
(I have linked obj models to LightGallery etc) :slight_smile:

	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, MyObjGroup, MyLineGroup, MyAllLineGroup;
		
	function init() {

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

        AllModelGroup = new THREE.Group;
        AllModelGroup.name = 'AllModelGroup';
        scene.add( AllModelGroup );

		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( 0, 50, 50 );

		// controls
		controls = new OrbitControls( camera, renderer.domElement );
			controls.minDistance = 1;
			controls.maxDistance = 100;
			controls.target.set(0,20,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 );

		initModel();

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

  // MODEL
const initModel = () => {

let mod2load=[ 'box1', 'box2'];

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

	let fname = mod2load[i], fpath='';

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.load( fname+'.obj', function ( mod3one ) {

		// local groups, individual for each loaded *.obj / mod3one, 
		// these local groups at the end of the loop are appended 
		// to the global group AllModelGroup
		MyObjGroup = new THREE.Group;
		MyLineGroup = new THREE.Group;
		MyAllLineGroup = new THREE.Group;

		MyObjGroup.name="MyObjGroup";			// mesh
		MyLineGroup.name="MyLineGroup";			// my lines
		MyAllLineGroup.name="MyAllLineGroup";	// all lines

		mod3one.traverse(function(node) {

		if ( node.isMesh ) {
			if (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' } ) );
				if (node.material.name =='yellow' ) {	
					MyLineGroup.add( line );
					// scene.add( line );					
				}else{
					MyAllLineGroup.add( line );					
					// scene.add( line );						
				}
			}
		}
		}); // mod3one.traverse ------------------------------

		// scene.add(mod3one);

	MyObjGroup.add( mod3one );		// add mesh to local group
	MyObjGroup.add( MyLineGroup );	// add mylines to local group

	MyAllLineGroup.visible=false;	// Hide all edges for the scene opening
	MyObjGroup.add( MyAllLineGroup );// add alllines to local group

	AllModelGroup.add( MyObjGroup );	// append the local group 
										// of the loaded obj 
										// to the global group 

	}); // .load( fname+'.obj' ------------------------------

	}); // .load fname+'.mtl' ------------------------------
	
} // for ------------------------------

}

init();
animate();


// CONSOLE ============================================================

console.log(scene);	// OK

let e=scene.getObjectByName( "AllModelGroup" );
console.log(e);	// OK

console.log(e.getObjectByName( "MyObjGroup" ));	// return undefined ?

// ... ?????

In theory, my scene structure looks like this:

scene
   Light
   Camera
   ...
   ...
   AllModelGroup
 		MyObjGroup (first *.obj)
 			mesh *.obj
 			MyLineGroup
 				my lines...
 			MyAllLineGroup
 				all lines...
 		MyObjGroup (second *.obj)
 			mesh *.obj
 			MyLineGroup
 				my lines...
 			MyAllLineGroup
 				all lines...

any hint how I could access child groups in AllModelGroup ?

// CONSOLE ============================================================
console.log(scene);	// OK
let e=scene.getObjectByName( "AllModelGroup" );
console.log(e);	// OK

console.log(e.getObjectByName( "MyObjGroup" ));	// return undefined ?
// ... ?????
```


grouptest_htmljsobjmtl.zip (4.0 KB)

Loading is asynchronous. When you request the loader to load a model, it is not available right away, but sometime later. Make the following test and see whether ‘object loaded’ text appears before or after you use getObjectByName.


Fun fact: it is considered a bad manner to add questions to a discussion outside its initial topic. Such questions should be asked in new threads in the forum.

1 Like

AFTER getObjectByName:

Object { isObject3D: true, uuid: "b199bb11-fee2-4f14-8dbb-5e4a3c84efb6", name: "", type: "Scene", parent: null, children: (3) […], up: {…}, position: {…}, rotation: {…}, quaternion: {…}, … }
grouptest.js:139:10
Object { isObject3D: true, uuid: "7acc62d3-9901-4e3b-9bdf-21a7817e8e8d", name: "AllModelGroup", type: "Group", parent: {…}, children: (2) […], up: {…}, position: {…}, rotation: {…}, quaternion: {…}, … }
grouptest.js:142:10
undefined grouptest.js:144:10
object loaded grouptest.js:83:13
object loaded

?

So, you have your answer.

You check for the subgroups before they are ever created. That’s why you cannot find them.

1 Like

I see !
Pavel THANK YOU VERY MUCH :slight_smile:
I included in the onWindowResize function:

   let e=scene.getObjectByName("AllModelGroup" );
  console.log(e.getObjectByName("MyObjGroup" ));

and after resizing the window the console started listing MyObjGroup
What is the workaround?
For example, do I have to use a for loop to check to wait:

    typof e.getObjectByName( "MyObjGroup" ) == 'object' etc

before I can do anything with MyObjGroup?
example:

	let e=scene.getObjectByName( "AllModelGroup" );
(function myWaiting() {
  setTimeout(function() {

	let ee=e.getObjectByName( "MyObjGroup" );
	if (typeof ee=='object'){
	console.log(ee);		// OK
	
	console.log(ee.children[0]);		// OK
	ee.children[0].visible=false;		// OK
	
	console.log(ee.getObjectByName( "MyLineGroup" ));		// OK
	console.log(ee.getObjectByName( "MyAllLineGroup" ));	// OK
	// etc
	}
  }, 200)	// after about 150-200 I have MyObjGroup available :)
})(); 

Yesterday I spent many hours trying to get to the contents of the AllModelGroup table - visible in the console but not available in js.
I admit that it’s a shock for me to use such tricks, unless there is another solution, but I don’t know enough :slight_smile:
OK, For my purposes, this is enough for now.