How to load an *.obj file, and make many 3DObject

How to load an *.obj file, and make many 3Dobject.

Hi, friends.
I’m trying to show many lamps in along a street, I use the following code first, it works, but slowly.

function initLamp(scene)
{
	var group=new THREE.Group();
	var lamp_objfile="res/obj/lamp.obj";

    //	var aLamp;
	var aLoader = new THREE.OBJLoader();
	for(var i=0;i<LampN.length;i++)
	{
		var acfg=LampN[i];
		initLamp1(scene,group,acfg);
	}
	scene.add(group);
}
function initLamp1(scene,group,acfg)
{
	var lamp_objfile="res/obj/lamp.obj";
	var aLoader = new THREE.OBJLoader();
		aLoader.load( lamp_objfile, function(obj) {
			obj.scale.set( 0.02, 0.02, 0.02 );
			obj.position.set( lon2z( acfg.pos[0] ),0, lat2x( acfg.pos[1] ) );
			obj.rotation.x = deg2rad( 90  );
			obj.rotation.y = deg2rad( 180 );
			obj.rotation.z = deg2rad( 0   );

			var material=new THREE.MeshLambertMaterial( {color:0x00c0c0} );
			obj.children.forEach(
				function (child) {
					child.material = material;
				}
			);
			group.add(obj);
			}
		);
}

and now I’m try the following

function initLamp(scene)
{
	var group=new THREE.Group();
	var lamp_objfile="res/obj/lamp.obj";

	var aLoader = new THREE.OBJLoader();
		aLoader.load( lamp_objfile, function(obj) {
			obj.scale.set( 0.02, 0.02, 0.02 );
			obj.position.set( 0,0, 0 );
			obj.rotation.x = deg2rad( 90  );
			obj.rotation.y = deg2rad( 180 );
			obj.rotation.z = deg2rad( 0   );

			var material=new THREE.MeshLambertMaterial( {color:0x00c0c0} );
			obj.children.forEach(
				function (child) {
					child.material = material;
				}
			);
			lamp0=obj;
			}
		);

	for(var i=0;i<LampN.length;i++)
	{
		var acfg=LampN[i];
		var newobj=lamp0.clone();
		newobj.position.set( lon2z( acfg.pos[0] ),0, lat2x( acfg.pos[1] ) );
		group.add(newobj);
	}
	scene.add(group);
}

I wanted to load the *.obj file only once and can use it to make many target to make the page much faster.

who can help me? thanks.

Hi @buffalo, and welcome to the forum :smile:
I’ve formatted code blocks for you. Please “edit” your post to see how it’s done.

Your second attempt looks ok, although you’ll be limited in how many times you can clone the lamp before running into performance issues. How many lamps do you want?

Some techniques that are often used in this situation:

  1. merge the geometry of all the lamps so that you have a single object.
  2. use instancing (use one geometry and duplicate it on the GPU). You can see some examples here.
  3. use LOD so further away lampposts get replaced with more simple geometry. Example here. In this case, you’ll have to create one or more simplified versions of the model in a modeling program.
1 Like

thanks for your reply. it’s very helpful for me. because I’m a real newer to WebGL, hope to get your more help in the future.

and now I have found out why I can’t get more than one object. because we use a callback function so the first object hasn’t been initialized when I try to clone it.

Oops, I missed that in your code. Yes, you’re totally right.
If you’re familiar with using async/await you can load the model without callbacks:

async function initLamp(scene) {
  const group = new THREE.Group();
  scene.add(group);

  const loader = new THREE.OBJLoader();
  const lampModel = await loader.loadAsync('res/obj/lamp.obj');
  lampModel.scale.set(0.02, 0.02, 0.02);
  lampModel.position.set(0, 0, 0);
  lampModel.rotation.x = THREE.MathUtils.deg2rad(90);
  lampModel.rotation.y = THREE.MathUtils.deg2rad(180);
  lampModel.rotation.z = THREE.MathUtils.deg2rad(0);

  const material = new THREE.MeshLambertMaterial({ color: 0x00c0c0 });
  lampModel.children.forEach((child) => (child.material = material));

  for (let i = 0; i < LampN.length; i++) {
    const acfg = LampN[i];
    const newobj = lampModel.clone();
    newobj.position.set(lon2z(acfg.pos[0]), 0, lat2x(acfg.pos[1]));
    group.add(newobj);
  }
}
1 Like

thanks a loat.
async/await? load the model without callbacks?
I tried your code and get following message at this line :

const lampModel = await loader.loadAsync(‘res/obj/lamp.obj’);

ERROR:
Uncaught (in promise) TypeError: loader.loadAsync is not a function

it seems that there was some new version three.js?

Yeah it’s available since r118 I think.

ok, I get it, thanks :slight_smile: