Jump to content

[SOLVED] How to add OBJ files dynamically in scene


dbawel
 Share

Recommended Posts

Hello,

I hope someone knows how to do this - I need to have a scene running, and also a scanner beside it. As scanned heads are added to the scene as OBJ files, I need them loaded and rendered in the scene without disposing of the scene. The paths to the new files must be added to an array.

I currently have a test scene online, and am loading 2 heads at the start. Then I have a left mouse event add a new file path and folder to the array - but don't know how to tell the loader to load again from the new path. I can delete any path in the array which has already had an OBJ loaded from it, as the path will only be used once. The online scene is below - it might need to be loaded twice the first time.

http://qedsoft.com/SBSW/10_heads/index.html

The main JS code is as follows:

Quote

 

    var canvas = document.getElementById("renderCanvas");
    var engine = new BABYLON.Engine(canvas);
    var scene = new BABYLON.Scene(engine);
    
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    
    var camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(-2.15, 0, -3.2), scene);
    camera.MIN_VALUE = 0.01
    
    var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 5, -5), scene);

var pathsToLoadFrom = ["./assets/obj_files_10/", "./assets/obj_files_11/"];
    
document.addEventListener("mousedown", push_path, false);

function push_path(evt) {
    pathsToLoadFrom.push("./assets/obj_files_12/");
}


    var mesh_pos = -5;

    
    if (pathsToLoadFrom.length > 0) {
        
        
    for (var p = 0; p < pathsToLoadFrom.length; p++) {
        

    
    
       let loader = new BABYLON.AssetsManager(scene);
        loader.useDefaultLoadingScreen = true;  // Set to false to remove the default loading
        let mesh_loaded_task = loader.addMeshTask("mesh" + p, "", pathsToLoadFrom[p], "mesh.obj");
        
    
        
        mesh_loaded_task.onSuccess = function (task) {
             task.loadedMeshes.forEach(function(m) {
                console.log("Loaded!");
                m.position.x = mesh_pos += 0.5;
                m.rotation = new BABYLON.Vector3(0, 0, 179.05);
                console.log(m);
             });
        };


        
        loader.onFinish = function() {
            engine.runRenderLoop(function () {
                scene.render();
            });
        };

        loader.load();
        
    }
    }

 

I appreciate it if you can assist.

Thanks,

DB

Link to comment
Share on other sites

you can dynamically load OBJ files on the fly - I don't think the MTL will be loaded here yet:

BABYLON.SceneLoader.ImportMesh(
  '',
  'folder/',
  'file.obj',
  scene,
  loadedMeshes => {
    loadedMeshes.forEach(loadedMesh => {
      console.log(`loaded '${loadedMesh.name}'`, loadedMesh)
      this._loadedMeshes.push(<BABYLON.Mesh> loadedMesh);
    });
  }
);

 

Link to comment
Share on other sites

Hi @brianzinn -

I've tried to implement several ways, and have not been successful yet. I can't find this in the documentation, but the logic makes sense. So as long as I push a loaded mesh into the loadedMeshes array, it should display while a scene is already rendering? And any thoughts on loading the MTL? Thanks for helping, I really need it right now. I'm stuck at a Starbucks off the freeway which is now closed due to mudslides.

If there's any additional info, I'd be grateful - especially how I might load the MTL file if it doesn't load automatically. However, I still need to get the OBJ files loaded,and my problem is that the path will come from an array.

Thanks much - I'll keep trying.

DB

Link to comment
Share on other sites

this.loadedMeshs = [];
//If you want to keep object scope:
var self = this;

BABYLON.SceneLoader.ImportMesh(
  '',
  'folder/',
  'file.obj',
  scene,
  (meshes)=> { 
    for(var i=0; i<meshs.length; i++){
      var mesh = meshes[i];
       console.log(mesh);
       self.loadedMeshs.push(mesh);
     }
  }
);

That syntax would never of worked.

Link to comment
Share on other sites

My example was copied from working code.  Both ways should work, do you have an array declared to push to - this first line in @Pryme8's example?

You don't need "self" with fat arrow :) So, I don't believe that was why it was not working...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
"An arrow function does not have its own this; the this value of the enclosing execution context is used."

Link to comment
Share on other sites

Yup, which would have scope of the window then... this syntax is wrong.

this._loadedMeshes.push(<BABYLON.Mesh> loadedMesh);

is all sorts of wrong logic... first why would you push to the array your iterating through the same mesh that you are looping through?  Sounds like infinite recursion to me.
 

Link to comment
Share on other sites

I think it's unfair to say the syntax is wrong and there is "all sorts of wrong logic" without trying it yourself.  Perhaps you are not familiar with how classes work to encapsulate logic.    Here is the same code unchanged and working:
https://www.babylonjs-playground.com/#C02KIC

25 minutes ago, Pryme8 said:

Yup, which would have scope of the window then...

I think you are confusing window scope and enclosing scope.  I would just refer you to same MDN link :) 

@dbawel - the callback is a good place to rotate/position/etc if you can do it all there, but if you want to change it later just have a variable with external scope and it will be available afterwards or you can use a class like I did in the PG, but note that the load is asynchronous, so not available right after ImportMesh.

Cheers.

Link to comment
Share on other sites

dude, I can prove it to you... first off
BABYLON.SceneLoader.ImportMesh
Is in window scope...


and your first code was wrong then because:
 

class BotLoader {
constructor(folder, file) {
this.meshes = []
console.log(`loading" ${folder}${file}...`);
BABYLON.SceneLoader.ImportMesh("", folder, file, scene, meshes => {
meshes.forEach(mesh => {
console.log(`mesh: ${mesh.name}`, mesh)
this.meshes.push(mesh);
})
});
}
}

IS WAY DIFFERENT!

and yes now you have
encapsulate  scope... with this set up... which points the this to BotLoader instance...

your original post had its scope pointing to the window though...  

https://www.babylonjs-playground.com/#C02KIC#1

Argue with me about scope some more, its fun...
Link to comment
Share on other sites

2 minutes ago, dbawel said:

Hey @Pryme8

I can set transforms there, but can't define how to incrementally position each head after I add each one (at a different time) so the models don't overlap.

Thanks,

DB 

have a running value variable outside of the scope of the function so it does not get overwritten.

Link to comment
Share on other sites

8 minutes ago, brianzinn said:

The code snippet to answer the question is 100% identical! :) But I have to concede that the full context does change things.  Glad the problem is solved. Cheers.

not its not, the scope is different... the second you added an encapsulating object it changed the way the syntax reacted.

That's like saying a submarine performs the same in as out of the water...

I can also show proof of breaking the fat arrow's scope depending on when you define the function but that's a whole other discussion.

Link to comment
Share on other sites

Hey @Pryme8

I can't make a playground scene because I can't call the OBJ files or more specifically the paths to them. But the scene and code are below:

http://qedsoft.com/SBSW/10_heads/index.html

The code is rough test code, and I have it calling a new path and mesh on a mousedown event.

Quote

 

    var canvas = document.getElementById("renderCanvas");
    var engine = new BABYLON.Engine(canvas);
    var scene = new BABYLON.Scene(engine);
    
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    
    var camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(-2.15, 0, -3.2), scene);
    camera.MIN_VALUE = 0.01
    
    var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 5, -5), scene);

    var mesh_pos = -5;

var pathsToLoadFrom = ["./assets/obj_files_10/", "./assets/obj_files_11/"];
    
document.addEventListener("mousedown", push_path, false);

function push_path(evt) {
    pathsToLoadFrom.push("./assets/obj_files_12/");
    
this.loadedMeshs = [];
var self = this;
    
BABYLON.SceneLoader.ImportMesh(
  '',
  './assets/obj_files_12/',
  'mesh.obj',
  scene,
  (meshes)=> { 
    for(var i=0; i<meshes.length; i++){
      var mesh = meshes;
      mesh.rotation = new BABYLON.Vector3(0, 0, 179.05);
      mesh.position.x = messh_pos += 0.5;
       console.log(mesh);
       self.loadedMeshs.push(mesh);
     }
  }
);    
}

    
    if (pathsToLoadFrom.length > 0) {
        
        
    for (var p = 0; p < pathsToLoadFrom.length; p++) {
        

    
    
       let loader = new BABYLON.AssetsManager(scene);
        loader.useDefaultLoadingScreen = true;  // Set to false to remove the default loading
        let mesh_loaded_task = loader.addMeshTask("mesh" + p, "", pathsToLoadFrom[p], "mesh.obj");
        
    
        
        mesh_loaded_task.onSuccess = function (task) {
             task.loadedMeshes.forEach(function(m) {
                console.log("Loaded!");
                m.position.x = mesh_pos += 0.5;
                m.rotation = new BABYLON.Vector3(0, 0, 179.05);
                console.log(m);
             });
        };


        
        loader.onFinish = function() {
            engine.runRenderLoop(function () {
                scene.render();
            });
        };

        loader.load();
        
    }
    }

 

Thanks

DB

Link to comment
Share on other sites

var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas);
var scene = new BABYLON.Scene(engine);

scene.clearColor = new BABYLON.Color3(1, 1, 1);
var camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(-2.15, 0, -3.2), scene);
camera.minZ = 0.01;
var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 5, -5), scene);

var pathsToLoadFrom = ["./assets/obj_files_10/", "./assets/obj_files_11/", "./assets/obj_files_12/"];
    
//document.addEventListener("mousedown", push_path, false);


loader = function(paths){
	this.mesh_pos = -5;
	this.meshs = [];
	for(var i=0; i<paths.length; i++){
		this._run(paths[i]);
		this.mesh_pos += 1;
	}
	
	return this;
};

loader.prototype = {
	_run = function(path){
		var self = this;
		BABYLON.SceneLoader.ImportMesh('', './', path, scene, (meshes)=> {
			for(var i=0; i<meshes.length; i++){
				var mesh = meshes[i];
				mesh.position.x = self.mesh_pos;
				self.meshs.push(mesh);
			}
		});
	}
};
        
  	
engine.runRenderLoop(function () {
   scene.render();
});

var _l = new loader(pathsToLoadFrom);
      
        
    }
}


This is off the top of my head and prolly will drop an error... I have no clue I have not tested it.
But you had a lot of redundant stuff and things that were not effectively doing anything.

Link to comment
Share on other sites

document.addEventListener("DOMContentLoaded", ()=>{

var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas);
var scene = new BABYLON.Scene(engine);

scene.clearColor = new BABYLON.Color3(1, 1, 1);
var camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(-2.15, 0, -3.2), scene);
camera.minZ = 0.01;
var light = new BABYLON.PointLight("light", new BABYLON.Vector3(0, 5, -5), scene);

var pathsToLoadFrom = ["./assets/obj_files_10/", "./assets/obj_files_11/", "./assets/obj_files_12/"];
    
//document.addEventListener("mousedown", push_path, false);


loader = function(paths){
	this.mesh_pos = -5;
	this.meshs = [];
	for(var i=0; i<paths.length; i++){
		this._run(paths[i]);
		this.mesh_pos += 1;
	}
	
	return this;
};

loader.prototype = {
	_run : function(path){
		var self = this;
		BABYLON.SceneLoader.ImportMesh('', './', path, scene, (meshes)=> {
			for(var i=0; i<meshes.length; i++){
				var mesh = meshes[i];
				mesh.position.x = self.mesh_pos;
				self.meshs.push(mesh);
			}
		});
	}
};
        
  	
engine.runRenderLoop(function () {
   scene.render();
});

var _l = new loader(pathsToLoadFrom);

 }, false);     

Give that a shot. Should work.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...