Hi all, I’m completely new to JS and THREE. I’m working on a project and was hoping somebody could point me in the right direction. I have an OBJ file with an associated MTL file that references .png files for textures. I currently just have the model loaded in my project with none of the textures that should be associated with it. I was able to find some helpful resources online on how to get textures stored in .png files inside the script, but am struggling on how to get that incorporated into the model. Pasted below is the relevant blocks of code.
$( document ).ready(function() {
var scene, camera, clientClickX, clientClickY, renderer, selectedObj, INTERSECTED, mixer, clips;
var animationModel, selectModel;
var mouse = new THREE.Vector2();
var hoveredColor = 0x00FFFF;
var selectedColor = 0x39FF14;
var whiteColor = 0xffffff;
var objects = []; ...
//I know from the the texture loader documentation, I need something like this as well:
var textureLoader = new THREE.TextureLoader();
const materials = [
new THREE.MeshBasicMaterial({map: textureLoader.load('models/ArmsMap_t_2048.jpg')}),
new THREE.MeshBasicMaterial({map: textureLoader.load('models/EyesMap_512.jpg')}),
new THREE.MeshBasicMaterial({map: textureLoader.load('models/FaceMap_2048.jpg')}),
new THREE.MeshBasicMaterial({map: textureLoader.load('models/Hair_png_1024.jpg')}),
new THREE.MeshBasicMaterial({map: textureLoader.load('models/LegsMap_t_2048.jpg')}),
new THREE.MeshBasicMaterial({map: textureLoader.load('models/TorsoMap_t_2048.jpg')}),
];
//This is the current model loader but I think that I need to wrap this fxn in a MTLLoader?
var loader2 = new THREE.OBJLoader();
loader2.load('models/body_model.obj', function ( object ) {
object.children.forEach(child => {
objects.push(child);
changeObjectColor(child, whiteColor);
});
selectModel = object;
scene.add(object);
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
Let me know if this makes any sense Thanks!
Hi, welcome to the forum,
I know it doesn’t really answer your question, but if you use materials that reference textures for this model, did you consider loading it as a GLTF file instead of an OBJ ?
As written in the doc, this is the recommended file format with three.js as it is fast to load and incorporate materials. GLB version of this file format incorporate the texture so you don’t have to bother about referencing and serving them.
Use Blender to load your OBJ file, create materials with textures and export a GLB file incorporating all of this in a single binary file.
Load a GLTF or GLB file in three.js with GLTFLoader.
Hi! Thanks for the response. Can a GLTF or GLB file be interactive as well? The goal thus far was to be able to click into the object in different pieces. So if you imagine a cube, being able to click on one side of the cube. Does that make sense? That was the reasoning behind that. The .obj file I have right now, I’m getting an error when trying to import into blender. I know that the file works, because I’ve seen it - just not inside blender. It was created on a different platform
You can use a model loaded as GLTF or GLB in just the same ways, the loaded model will be converted to a Mesh, you just don’t have to bother about loading a material on the side, since the information for it will be embedded in the same file.
I can’t see why you would not be able to import an OBJ file in Blender, I do that a lot myself. Check that you have the last version of Blender, and if the problem persists ask for help in the Blender community.
Thanks for the insight! Really appreciate it. Turns out there was a problem with the file itself. It was created in cinema4d and apparently has issues exporting it. I’ll look into GLTF tho, seems like less hassle.
If you want to manually set the images used by an OBJLoader, rather than using the MTLLoader. You can create the MTLLoader.MaterialCreator manually.
See this example at line 28
At lines 29, 30-34 and 35-48, I manually set a material with the key “Material.001”. (You can uncomment which ever one you want to see)
This is the name of the material that is asked for in the raw .obj file loaded in this example at line 1575.
At line 51, I call the objLoaders setMaterials method and pass it an object called materialCreator which contains another object of materials where the key name matches the name of the material written in the raw .obj file. This object is a type of MTLLoader.MaterialCreator which I created manually beginning at line 28.
If you use the MTLLoader, it will load the .mtl file that you’ve set, and the MTLLoader.MaterialCreator that is passed to the OBJLoader in the next step would have been created automatically.
Visit https://sbcode.net/threejs/loaders-mtl/#srcclientclientts lines 24-50
to see my example of using the MTLLoader to automatically create the MTLLoader.MaterialCreator from the chosen .mtl file that was created when I exported my model from Blender. Blender is the ants pants.
Thank you! Your YouTube video on this was very helpful. Thanks again.
Hi @felixmariotto I was running into issues with performance as you alluded to. I decided to go your route and use GLB instead. This is the code I was running to highlight the parts of of my obj. I got it to work with MTL, but like you mentioned, materials were off and it was slow to load. I am running into issues here. Here’s the code that worked with my obj +mtl
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath('models/');
mtlLoader.load( 'body_model.mtl', function( materials ) {
materials.preload();
var loader = new THREE.OBJLoader();
loader.setMaterials( materials );
loader.setPath('models/');
loader.load( 'body_model.obj', function ( object ) {
object.children.forEach(child => {
objects.push(child);
changeObjectColor(child, whiteColor);
});
selectModel=object;
scene.add(object);
});
});
Code that I ignorantly thought would be the same xD: When I run this code in my program, it loads nothing. Let me know if you see something wrong, or how the right way to write this code would be.
var bodyLoader = new THREE.GLTFLoader();
bodyLoader.load('models/body_model.glb', function (gltf) {
gltf.children.forEach(child => {
gltfs.push(child);
changegltfColor(child, whiteColor);
});
selectModel = gltf;
scene.add(gltf);
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
What am I doing wrong?
Try console.log( gltf )
in your callback function, you will see that the object returned after loading is not the model, but an object containing various information including your model in gltf.scene
.
When you have an issue with three.js, you can also look into the doc, which is very complete and well written. The answer to your last question could have been found in GLTFLoader article