I have a zip that I fetch server side - from there I return a list of urls to the client. This list of file path contains an obj file, the textures, and material files. Is it possible to load these separately i to three js? I see a setPath method on the obj and mtl loaders but these files wont be in a directory so relative pathing won’t work.
Consider using a LoadingManager to adjust the paths as needed:
var manager = new THREE.LoadingManager();
manager.setURLModifier((url) => {
return url.replace('/foo/', '/bar/');
});
var loader = new THREE.OBJLoader(manager);
loader.load( ... );
three.js r91
Related
I exported an object from Blender to a gltf-file and imported it into my three.js project. (Including materials, ive got 2 in total)
let loader = new THREE.GLTFLoader();
loader.load('Objects/MyBox.gltf', (gltf) => {
let box = gltf.scene;
box.traverse((child) => {
if (child.isMesh) child.material = boxMaterial; // a material i created in the code earlier
});
scene.add(box);
});
This code causes my imported Object (which is a folded box) to have the same material (boxMaterial) on the outside and on the inside.
But as i created it in bleder ( inside of the box has an inside material, the outside has an outside material) i want it to be in my three.js project. What I want is = the boxMaterial(created in three.js) shall only be on the outside-Material(created in blender).
My question is -> how do I tell/access the specific imported material of my imported object to have a certain material in three.js?
In easier words: My "child.material" contains my needed materials from blender.(2 in total) But how do I access only the first one?
I think I'm looking for something like box.children[0].material.. or so. The index 0 is my outside material.
Thanks in advance!
I have seen plenty of examples on how to export a mesh or a whole scene from ThreeJS to an OBJ file. Starting from MrDoob example here:https://threejs.org/examples/#misc_exporter_obj
But since a marching cube like this : https://threejs.org/examples/webgl_marchingcubes.html is not an instance of THREE.Mesh, what would be the workaround to export its current geometry into an Obj file? And by extension its material into an mtl file as explained in this question : Export a three js textured model to a .OBJ with .MTL file
EDIT
As far as I understand, it is possible to export a copy of the current state of the metaballs by using the generateGeometry() function provided by marching cubes. Below is an example using filesaver.js and JSZip.js to export the geometry and material as two files in a zip. THREE.OBJExporter comes from the modified version of the original obj exporter of threeJS done as mentionned above (Export a three js textured model to a .OBJ with .MTL file):
function exportToObj(the_object){
var zip = new JSZip();
var the_exporter = new THREE.OBJExporter();
var result = the_exporter.parse(the_object);
zip.file("Blob.obj", result.obj);
zip.file("Blob.mtl", result.mtl);
zip.generateAsync({type:"blob"}).then(function (blob) {
saveAs(blob, "Blob.zip");
});
}
$(document).on('keyup',function(e) {
if (e.which == 13){ // enter key to export to OBJ
var TempMesh = new THREE.Mesh(effect.generateGeometry(),effect.material);
//effect is of the type: new THREE.MarchingCubes()
exportToObj(TempMesh);
}
});
In that way, if a color is provided to the material, it will be exported in the .mtl file. But the last missing piece is probably how to properly convert a shaderMaterial for example? Save it as a texture maybe?
I need to implement a functionality where user can upload a OBJ 3D model and then I will show different sub-parts of that model in browser. (Same as https://www.sculpteo.com is doing.).
But I am unable to find sub-parts of OBJ model. I am using three.js to show OBJ model in browser.
Is there any way to find sub-parts to OBJ model using three.js?
I am sharing code to load OBJ model =>
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( 'path' );
mtlLoader.load( 'model.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'path' );
objLoader.load( 'model.obj', function ( object ) {
scene.add( object);
});
});
Now I don't know how to find sub-parts of this "model.obj". Kindly help. Thanks in advance.
OJBLoader returns (THREE.Object3D() (it was in r71)) THREE.Group() (r81) with children of THREE.Mesh.
You'll get sub-parts as child meshes of the object only if your .obj file has groups of objects. Without it, you'll get just a sinlge child mesh.
Read about Wavefront .obj file format.
So, if your data of sub-parts grouped under
o [object name]
tag, then you'll have as many child meshes as you have "o" groups in your .obj file and then you can traverse.
upd#1: It also works with "g" tags.
g [group name]
The example based on "webgl_interactive_cubes" from Threejs.org, the data of sub-parts grouped with "g" tags (skull, uteeth, jaw, lteeth) in the .obj file
When you load the objects you can do this inside your callback function :
objLoader.load('yourUrl.obj', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
console.log(child);
// here you can make what you want with the children of object
}
});
});
I have an export of some .obj files and corresponding .mtl files. Textures are in .tga format in the same folder.
Here is the code I use to load all my .obj:
function addCar(modelPath, modelName) {
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath(modelPath);
for (var i = 0; i <= 2; i++) {
loadObject(mtlLoader, modelPath, modelName, i);
}
}
function loadObject(loader, path, name, i) {
var objectName = name + i + '.obj';
loader.load(name + i + '.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath(path);
objLoader.load(objectName, function (object) {
scene.add(object);
}, function (xhr) {
onProgress(xhr, objectName)
}, onError);
});
}
The car is loaded, but not the textures. It appears all white, and there is no error in the console. I tried to add
mtlLoader.setTexturePath(modelPath);
but it didn't change anything.
I also tried to add
THREE.Loader.Handlers.add( /\.tga$/i, new THREE.TGALoader() );
before to call addCar function. When I do that, some warning appears in the console, but texture still doesn't appear.
In all examples I saw, textures are loaded automatically when using OBJLoader and MTLLoader, but I didn't any example using OBJLoader and MTLLoader with TGA textures. So I'm wondering if there is something to do to get it worked.
Any help would be appreciated.
PS: the files (.obj, .mtl and .tga) are exported from 3D max).
You'll have to use the TGALoader to load .tga files. You can find it here.
See the webgl_materials_texture_tga source for an example.
Is there a reason why you are using a .tga texture instead of .png? For most purposes they will give identical results, and .png will generally be smaller and can be natively decoded by the browser so you'll get better performance.
If the number of files is not very big: change the mtl file's content, make 'tga' to 'jpg', then I use photoshop to make every tga file to jpg file.
I have a quite complex shape (dressed girl) that in Blender is broken down into different objects and it's loaded into Three.js with the JSON loader (with a little hack I made, that uses zipped files instead of just JSON files, as there are a lot of vertices).
As I want to change dynamically the style of the dress from a Web page, I was wondering how I can show/hide different pieces (e.g. sleeves) in the scene.
I tried traversing the THREE.Mesh, but there are no children.
When I export from Blender with the JSON exporter, I don't see anything referring to the names of the objects in the JSON. Is the structure lost?
If you are using meshes containing lots of vertices, I would advise you to use the openCTM webGL loader instead of zip hacking. Here is a link to the loader : http://threejs.org/examples/webgl_loader_ctm.html
This mesh compression tool uses LZMA compression method and can reduce the size of your files by 93%...
Concerning the JSONLoader, using an array might help:
var meshes = [];
...
var loader = new THREE.JSONLoader();
var onGeometry = function(geom)
{
var mesh = new THREE.SceneUtils.createMultiMaterialObject(geom, [material]);
meshes.push( mesh );
...
scene.add(mesh);
};
loader.load("yourfile.js", onGeometry);
Hope this helps
It is possible to load an entire scene with several meshes from a json file exported from Blender and handle them separately!
You can follow the complete process of exporting a entire scene from Blender and the right way of handling the exported meshes on my answer of this post.
So, you can get the different meshes and manipulate them separately using the getObjectByName method. But it is important to know that the loaded object isn't a Geometry anymore. It is labeled with the Scene type by now and it must be handled in a different way.
The loading code must look like this one:
loader = new THREE.JSONLoader();
loader.load( "obj/Books.json", function ( loadedObj ) {
var surface = loadedObj.getObjectByName("Surface");
var outline = loadedObj.getObjectByName("Outline");
var mask = loadedObj.getObjectByName("Mask");
scene.add(surface);
scene.add(outline);
scene.add(mask);
} );
Besides, you can handle the multiple materials of single mesh using THREE.MeshFaceMaterial like in the following code:
var mat1 = new THREE.MeshLambertMaterial( { map: texture1 } );
var mat2 = new THREE.MeshLambertMaterial( { map: texture2 } );
var materials = [mat1, mat2];
var faceMat = new THREE.MeshFaceMaterial(materials);
mesh = new THREE.Mesh( geometry, faceMat );
scene.add( mesh );
Hope this helps :)