Three js Progress loading OBJMTLLoader - javascript

I am wanting a method to get the loading progress of .obj and .mtl file in three.js.
In previous version (as r53) I do that with:
loader = new THREE.OBJMTLLoader();
loader.addEventListener('progress', function ( item ){
console.log( item.loaded, item.total, item );
});
but now, using version r67 I can´t do that whith this code.
I try with:
var loader = new THREE.OBJMTLLoader();
loader.load( 'obj/inicial/modelo.obj', 'obj/inicial/modelo.mtl', function(object){
scene.add( object );
}, function(item){
console.log(item);
});
but it doesn´t works.
I searched google but have not found anything about. Can someone help me?
Thans in advance.

Both LoadingManager and onProgress callbacks should/will be available in dev and in master soon, hopefully.
For onProgress, onError in OBJMTLLoader
https://github.com/mrdoob/three.js/pull/5423
For LoadingManager support
https://github.com/mrdoob/three.js/pull/5463

The OBJMTLLoader class is deprecated, instead the latest three.js (r78) uses MTLLoader plus OBJLoader, codes are something like below:
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( 'obj/male02/' );
mtlLoader.load( 'male02_dds.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'obj/male02/' );
objLoader.load( 'male02.obj', function ( object ) {
object.position.y = - 95;
scene.add( object );
}, onProgress, onError );
});

Related

How to add a material (.mtl) to an object (.obj) using three.js?

I have successfully gotten a .obj file to display using three.js from a snippet of code I found online which I adapted for my needs. But am now trying to add the .mtl material file and am getting stuck.
I've tried a few things but nothing seems to be working. I am new to three.js so am definitely misunderstanding something here...
Here is the current code I am using that works beautifully to display my .obj file:
var renderer, scene, camera, Nefertiti;
var ww = window.innerWidth,
wh = window.innerHeight;
function init(){
renderer = new THREE.WebGLRenderer({canvas : document.getElementById('scene')});
renderer.setSize(ww,wh);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50,ww/wh, 0.1, 10000 );
camera.position.set(0,0,500);
scene.add(camera);
//Add a light in the scene
directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 0, 0, 350 );
directionalLight.lookAt(new THREE.Vector3(0,0,0));
scene.add( directionalLight );
//Load the obj file
loadOBJ();
}
var loadOBJ = function(){
//Manager from ThreeJs to track a loader and its status
var manager = new THREE.LoadingManager();
//Loader for Obj from Three.js
var loader = new THREE.OBJLoader( manager );
//Launch loading of the obj file, addNefertitiInScene is the callback when it's ready
loader.load( '/mypath/Nefertiti-3d.obj', addNefertitiInScene);
};
var addNefertitiInScene = function(object){
Nefertiti = object;
//Move the Nefertiti in the scene
Nefertiti.scale.set(0.7,0.7,0.7);
Nefertiti.rotation.x = 0.5;
Nefertiti.rotation.y = 5.5;
Nefertiti.rotation.z = 0.2;
Nefertiti.position.y = -40;
Nefertiti.position.z = 1;
//Go through all children of the loaded object and search for a Mesh
object.traverse( function ( child ) {
//This allow us to check if the children is an instance of the Mesh constructor
if(child instanceof THREE.Mesh){
child.material.color = new THREE.Color(0XFFFFFF);
//Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
child.geometry.computeVertexNormals();
}
});
//Add the 3D object in the scene
scene.add(Nefertiti);
var canvas = renderer.domElement;
canvas.addEventListener('mousemove', onMouseMove);
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
function onMouseMove(event) {
Nefertiti.rotation.y += event.movementX * 0.001;
Nefertiti.rotation.x += event.movementY * 0.0005;
}
};
init();
Here is a snippet I tried adding in to load the mtl file that didn't work (i've just shortened the actual path to /mypath/ for cleanliness here)
var loadOBJ = function(){
    var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl( '/mypath/' );
mtlLoader.setPath( '/mypath/' );
var url = "/mypath/Nefertiti-3d.mtl";
mtlLoader.load( url, function( materials ) {
    materials.preload();
    //Manager from ThreeJs to track a loader and its status
    var manager = new THREE.LoadingManager();
    //Loader for Obj from Three.js
    var loader = new THREE.OBJLoader( manager );
    loader.setMaterials( materials );
    loader.setPath( '/mypath/' );
    //Launch loading of the obj file, addNefertitiInScene is the callback when it's ready 
    loader.load( '/mypath/Nefertiti-3d.obj', addNefertitiInScene);
    object.position.y = - 95;
        scene.add( object );
    }, onProgress, onError );
};
From researching I can see that there must be a mesh for a material to work, but I just cant figure out from any documentation how I can correctly implement it.
Any assistance in being able to add a mtl file to my code would be so appreciated!!
** EDIT **
So I have changed the snippet of code based on the advice from Mugen87 to the below:
var loadOBJ = function(){
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( '/mypath/' );
var url = "/mypath/Nefertiti-3d.mtl";
mtlLoader.load( url, function( materials ) {
materials.preload();
//Manager from ThreeJs to track a loader and its status
var manager = new THREE.LoadingManager();
//Loader for Obj from Three.js
var loader = new THREE.OBJLoader( manager );
loader.setMaterials( materials );
loader.setPath( '/mypath/' );
//Launch loading of the obj file, addNefertitiInScene is the callback when it's ready
loader.load( '/mypath/Nefertiti-3d.obj', addNefertitiInScene);
}, onProgress, onError );
};
And I have also included the MTLLoader.js from the examples on three.js (I'm not sure if this is right, I'm finding it difficult to find information on this) and am getting the below errors in console:
Uncaught SyntaxError: Cannot use import statement outside a module
(index):136 Uncaught TypeError: THREE.MTLLoader is not a constructor
at loadOBJ ((index):136)
at init ((index):132)
at (index):199
loadOBJ # (index):136
init # (index):132
(anonymous) # (index):199
Any ideas? Is there something wrong with how I have the MTL in the code?
object.position.y = - 95;
scene.add( object );
I suppose you have copied over both lines of code from the official OBJ/MTL example, right? Unfortunately, they don't make sense here since object is undefined. Keep in mind that addNefertitiInScene is your onLoad() callback which is responsible for adding the loaded object to the scene.
Besides, mtlLoader.setBaseUrl( '/mypath/' ); should not be necessary. The method was removed quite a while ago.
Also ensure with the browser's dev tools that the MTL file is actually loaded.
three.js R109

Three.Js object file is loadded but material files are not loading

I created 1 small object file in the blender tool and then exported it to wavefront (.obj) format.
My code:
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( 'objs/' );
mtlLoader.load( 'final_blue_cup.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'objs/' );
objLoader.load( 'final_blue_cup.obj', function ( object ) {
scene.add( object );
}, onProgress, onError );
});
This is my output from my blender tool:
This is what is get after load in three.js:
With this link you can find my object, material and blender file: https://drive.google.com/drive/folders/1XW_teF6N3qqmqavsQrPpLZntJoMvqL0K
Can anyone help me in fixing it?

How to add the camera loaded by fbxloader to scene in three.js?

I'm using fbxloader of three.js to add model to my scene, and i've seen that the lastest version of fbxloader.js (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/FBXLoader.js) can read the camera data of .fbx file.
But how to add this camera to my scene?
Here is my current code which can only get the original model.
var loader = new THREE.FBXLoader( manager );
loader.load( 'url', function( object ) {
scene.add( object );
}, onProgress, onError );
You can do something like:
var loader = new THREE.FBXLoader( manager );
loader.load( 'url', function( object ) {
object.traverse( function( child ) {
if ( child instanceof THREE.Camera ) {
scene.add( child );
}
} );
scene.add( object );
}, onProgress, onError );
but you should now that the camera is already included in the scene.

Materials not correctly applying in MTLLoader

I have two separate models in which the first model's material gets loaded with the material of the second. Below I'm loading two separate models and material files with OBJLoader and MTLLoader:
MTLLoader.setPath( 'models/' );
var url = "model.mtl";
MTLLoader.load( url, function one( materials ) {
materials.preload();
OBJLoader.setMaterials( materials );
OBJLoader.setPath( 'models/' );
OBJLoader.load( 'model.obj', function ( object ) {
scene.add( object );
});
});
MTLLoader.setPath( 'models2/' );
var url2 = "model2.mtl";
MTLLoader.load( url2, function two( materials2 ) {
materials2.preload();
OBJLoader.setMaterials( materials2 );
OBJLoader.setPath( 'models2/' );
OBJLoader.load( 'model2.obj', function ( object ) {
scene.add( object );
});
});
I'm not specifying texture paths because the .mtl files links has the paths already. I know I'm doing this incorrectly but I can't find any solution for this anywhere. Why doesn't my first model get applied the correct material? I just want to correctly apply the respective material to its model.

JSONLoader and textures R61

I recently updated to version r61 from r58 and have found that with JSONLoader even if i only want to return geometry I am still getting a 404 on a texture call from a shader in my model.js file.
loadModel: function( label, domobject, callback ) {
var model_path = '/models/js/' + label + '.js';
var texture_place = '/textures/' + label + '.jpg';
var loader = new THREE.JSONLoader()
function onLoad(event) {
domobject.append( Set.renderer.domElement );
}
var texture = new THREE.ImageUtils.loadTexture( texture_place, null, onLoad );
loader.load( model_path, function ( geometry ) {
var material = new THREE.MeshLambertMaterial({map: texture});
Set.asset = new THREE.Mesh( geometry, material );
Set.asset.position.x = Set.asset.position.y = Set.asset.position.z = 0;
Set.asset.scale.x = Set.asset.scale.y = Set.asset.scale.z = 1;
if ( callback ) callback();
});
},
I am setup this way as to prevent models from loading up black and then having the texture pop on, which is working great. The behavior I expected with JSONLoader was that
loader.load(model_path, function (geometry, materials) would dig into the model file and look for materials and textures and that just specifying 'geometry' would ignore shader / texture.
Furthermore,
Is there a more simple way to use JSONLoader it's texturePath argument and an onLoad function to ensure that my geo doesn't get rendered before a texture is finished loading ?
Thanks!

Categories

Resources