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.
Related
I have been buying animated 3D models from TurboSquid and they fall into two starkly different categories:
Ready to use - I just load the FBX file and it looks fine in my ThreeJS scene
Missing textures - The loaded FBX model looks geometrically fine and the animations work, but all the surfaces are white
I want to know how to load the provided textures using the FBXLoader module. I have noticed that all of the FBX models, which I believe are PBR material based, have this set of files:
*002_BaseColor.png
*002_Emissive.png
*002_Height.png
*002_Metallic.png
*002_Roughness.png
*002_Normal.png
I have these questions:
How would I use the FBXLoader module to load the textures "in the right places"? In other words, how do I make the calls so that the BaseColor texture goes to the right place, the Emissive texture so it goes where it should, etc?
Do I need to pass it a custom material loader to the FBXLoader and if so, which one and how?
UPDATE: I trace through the ThreeJS FBX loader code I discovered that the FBX model that is not showing any textures does not have a Texture node at all. The FBX model that does show the textures does, as you can see in this screenshot of the debugger:
I'll keep tracing. If worse comes to worse I'll write custom code to add a Textures node with the right fields since I don't know how to use Blender to add the textures there. My concern is of course that even if I create a Textures node at run-time, they still won't end up in the proper place on the model.
This is the code I am currently using to load FBX models:
this.initializeModel = function (
parentAnimManagerObj,
initModelArgs= null,
funcCallWhenInitialized = null,
) {
const methodName = self.constructor.name + '::' + `initializeModel`;
const errPrefix = '(' + methodName + ') ';
self.CAC.parentAnimManagerObj = parentAnimManagerObj;
self.CAC.modelLoader = new FBXLoader();
self.CAC.modelLoader.funcTranslateUrl =
((url) => {
// Fix up the texture file names.
const useRobotColor = misc_shared_lib.uppercaseFirstLetter(robotColor);
let useUrl =
url.replace('low_Purple_TarologistRobot', `Tarologist${useRobotColor}`);
return useUrl;
});
// PARAMETERS: url, onLoad, onProgress, onError
self.CAC.modelLoader.load(
MODEL_FILE_NAME_TAROLOGIST_ROBOT_1,
(fbxObj) => {
CommonAnimationCode.allChildrenCastAndReceiveShadows(fbxObj);
fbxObj.scale.x = initModelArgs.theScale;
fbxObj.scale.y = initModelArgs.theScale;
fbxObj.scale.z = initModelArgs.theScale;
self.CAC.modelInstance = fbxObj;
// Set the initial position.
self.CAC.modelInstance.position.x = initModelArgs.initialPos_X;
self.CAC.modelInstance.position.y = initModelArgs.initialPos_Y;
self.CAC.modelInstance.position.z = initModelArgs.initialPos_Z;
// Create an animation mixer for this model.
self.CAC.modelAnimationMixer = new THREE.AnimationMixer(self.CAC.modelInstance);
// Speed
self.CAC.modelAnimationMixer.timeScale = initModelArgs.theTimeScale;
// Add the model to the scene.
g_ThreeJsScene.add(self.CAC.modelInstance);
// Don't let this part of the code crash the entire
// load call. We may have just added a new model and
// don't know certain values yet.
try {
// Play the active action.
self.CAC.activeAction = self.CAC.modelActions[DEFAULT_IDLE_ANIMATION_NAME_FOR_TAROLOGIST_ROBOT_1];
self.CAC.activeAction.play();
// Execute the desired callback function, if any.
if (funcCallWhenInitialized)
funcCallWhenInitialized(self);
} catch (err) {
const errMsg =
errPrefix + misc_shared_lib.conformErrorObjectMsg(err);
console.error(`${errMsg} - try`);
}
},
// onProgress
undefined,
// onError
(err) => {
// Log the error message from the loader.
console.error(errPrefix + misc_shared_lib.conformErrorObjectMsg(err));
}
);
}
I am loading a 3D model using 3 files I've been provided with:
example.obj
example.mtl
example.jpg
I am loading them in my Three.js script with this snippet:
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath('./');
mtlLoader.load('example.mtl', function(materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('./');
objLoader.load('example.obj', function(obj) {
scene.add(obj);
}, onProgress, onError);
});
The model is displayed on screen and the textures applied, but incorrectly (textures are not properly assigned to each face, look rotated, etc). Looks like the texture mapping is incorrect. Since the snippet is so simple and everything seems to be set automatically I'm not sure what I could do to try to fix it. Any idea?
BTW, the files were exported from Zbrush.
Thanks in advance
Thanks for the comments but I finally found out what the problem was: Zbrush was exporting the textures upside down. I corrected them and the issue was fixed. Thanks again.
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 display collada file (.dae) using three.js , i can load model but it display without textures , using this code
var loader = new THREE.ColladaLoader( loadingManager );
loader.options.convertUpAxis = true;
loader.load( './car.dae', function ( collada ) {
car = collada.scene;
car.material =
THREE.TextureLoader("../model/car_white.jpg");
i tried other codes ,only this code worked for model but without texture
need your support to add my texture.
Generally speaking, you can add textures to a model like this:
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('../model/car_white.jpg');
loader.load( './car.dae', function ( collada ) {
collada.scene.traverse(function (node) {
if (node.isMesh) {
node.material.map = texture;
}
});
});
Refer to the documentation for THREE.Material and THREE.TextureLoader for more information.
NOTE: As #gaitat mentioned in a comment, your texture may not be wrapped correctly on the model if they weren't designed for one another, and if the model isn't very simple. If that's the case, you probably need to add the texture in Blender (or other software) instead, where you can create UVs, and export the result.
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 :)