dbawel Posted January 11, 2018 Share Posted January 11, 2018 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 Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 11, 2018 Share Posted January 11, 2018 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); }); } ); Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 11, 2018 Author Share Posted January 11, 2018 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 Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 12, 2018 Share Posted January 12, 2018 The MTL will load but asynchronous. That code should show the mesh in your scene with the console.log at position (0,0). Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 Hi @brianzinn Everytime I push the new mesh, I receive a syntax error on the following line: this._loadedMeshes.push(<BABYLON.Mesh> loadedMesh); No matter how I set the syntax. What am I doing wrong? DB Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 12, 2018 Share Posted January 12, 2018 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." Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 @Pryme8- Your code works, but I don't know where to rotate, position, etc for the newly imported mesh. DB Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 inside the response function. the var mesh, you can manipulate or the Object.loadedMeshs array after the firing of the (meshs)=> response function. <3 Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 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 Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 dude, I can prove it to you... first offBABYLON.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... Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 @brianzinn and @Pryme8 Using a variable outside the function doesn't allow me to manipulate the transforms - although it should. But it certainly works inside the callback; but only once. DB Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 12, 2018 Share Posted January 12, 2018 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. Pryme8 1 Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 show me a PG Dave, Ill fix this up in 30 seconds for you. Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 **HIDE POST** unnecessary. Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 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 Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 check your typo messh_pos and give me a min. Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. Quote Link to comment Share on other sites More sharing options...
dbawel Posted January 12, 2018 Author Share Posted January 12, 2018 Hey @Pryme8 At line 27 which is _run = function(path){ , I receive and error in the console: SyntaxError: missing : after property id And can't seem to fix it. Here's the script with your code in place: http://qedsoft.com/SBSW/10_heads/index.html Thanks, DB Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 prolly simple syntax error give me a min ill fix. Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted January 12, 2018 Share Posted January 12, 2018 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. dbawel 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.