I have a problem. I wrote this function to load an obj and mtl model
(taken from:https://threejs.org/examples/#webgl_loader_obj_mtl):
var mtlLoader = new THREE.MTLLoader();
//mtlLoader.setTexturePath(path)
mtlLoader.setPath(path);
mtlLoader.load(material, function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath(path);
objLoader.load(model, function ( mesh ) {
mesh.position.set(x, y, z);
mesh.scale.set(s, s, s);
mesh.rotation.y = Math.PI;
mesh.castShadow = false;
mesh.receiveShadow = true;
scene.add(mesh);
if(handler) {
handler(mesh);
}
}, function(e){}, function(e){} );
});
Where material is file.mtl and model is file.obj. It works fine for this model: https://free3d.com/3d-model/hk416-with-animation-37927.html but it doesn't work for another obj+mtl. The texture is not loaded and I see only white model. Why?
I use three.js r85.
Thank you!!
Related
So I'm trying to upload a .obj file that also has multiple .png and .jpg files that are it's textures. The problem is I'm not sure how to even handle all these textures when they are uploaded.
Heres my code so far:
var loader = new THREE.OBJLoader(manager);
loader.load(obj_path, function (obj) {
model = obj;
modelWithTextures = true;
model.traverse( function ( child ) {
if ( child.isMesh ) child.material.map = texture;
} );
var textureLoader = new THREE.TextureLoader( manager );
var i;
for (var i = 0; i < files.length; i++) {
file = files[i];
console.log('Texture Files:' + files[i].name);
var texture = textureLoader.load(files[i].name);
}
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
setCamera(model);
setSmooth(model);
model.position.set(0, 0, 0);
setBoundBox(model);
setPolarGrid(model);
setGrid(model);
setAxis(model);
scaleUp(model);
scaleDown(model);
fixRotation(model);
resetRotation(model);
selectedObject = model;
outlinePass.selectedObjects = [selectedObject];
outlinePass.enabled = false;
renderer.render( scene, camera );
scene.add(model);
});
As you can see I'm using the textureLoader but just not sure what to do.
I'm very new to threeJS and 3d models.
Any help or advice would be much appreciated.
Thank you.
In your code, you probably won't see very much, because you render the scene before you add the model to the scene. You should render the scene after you did any changes (unless you have a render loop with requestAnimationFrame). Loading textures also is asynchronous. Use the callback of the .load method to better react when things are finished loading, e.g. trigger render().
I would load the textures within model.traverse() callback. But you have to determine which texture belongs to which mesh. This depends on how your data is structured.
var files = ['mesh1_tex.jpg', 'mesh2_tex.jpg'];
var loader = new THREE.OBJLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, -100); // depends on the size and location of your loaded model
var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
var scene = new THREE.Scene();
loader.load(obj_path, function ( model ) {
model.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
// here you have to find a way how to choose the correct texture for the mesh
// the following is just an example, how it could be done, but it depends on your data
const file = files.find( f => f === child.name + '_tex.jpg');
if (!file) {
console.warn(`Couldn't find texture file.`);
return;
}
textureLoader.load(file, ( texture ) => {
child.material.map = texture;
child.material.needsupdate = true;
render(); // only if there is no render loop
});
}
} );
scene.add( model );
camera.lookAt( model ); // depends on the location of your loaded model
render(); // only if there is no render loop
});
function render() {
renderer.render( scene, camera );
}
Disclaimer: I just wrote down this code without testing.
I am trying to add a level .obj for my program but it renders black. The .mtl file requires several images placed everywhere (not one space is non-textured). I used to same object in my last project and it works, but it doesn't in my current project. When I remove the materials the lighting affects it, but when I add it, it is pitch black. The renderer renders continously. Also, there are no errors in the console.
Here is the code used in my current project: (MaterialLoader is an MTLLoader instance and ObjectLoader is an OBJLoader instance)
MaterialLoader.load("bbb/bbb.mtl",
function(materials) {
materials.preload()
ObjectLoader.setMaterials(materials)
ObjectLoader.load("bbb.obj",
function(model) {
let mesh = model.children[0]
scene.add(mesh)
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
)
Here is the code from my previous project (the loader variable is an OBJLoader instance, and the materials load successfully here.)
mtlLoader.load(
"bbb.mtl",
function(materials) {
materials.preload()
loader.setMaterials(materials)
loader.load("bbb.obj",
function(obj) {
level = obj.children[0]
scene.add(level)
}, null,
function(error) { alert(error) }
)
}, null,
function(error) { alert(error) }
)
https://discourse.threejs.org/t/objloader-mtlloader-not-loading-texture-image/2534
try change object material color, like this:
model.children[0].material.color.r = 1;
model.children[0].material.color.g = 1;
model.children[0].material.color.b = 1;
its work for me
Your code works when tested! Maybe it's an issue with the material export, uv unwrapping, the texture's path, do you have lighting added to the scene, etc. Here's my test code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,320/240,1,500);
camera.position.set( 0,2,2 );
camera.lookAt( scene.position );
var lightIntensity = 1;
var lightDistance = 10;
var light = new THREE.AmbientLight( 0xFFFFFF, lightIntensity, lightDistance );
light.position.set( 0, 5, 0 );
scene.add( light );
var grid = new THREE.GridHelper(10,10);
scene.add( grid );
var renderer = new THREE.WebGLRenderer({});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( 320,240 );
renderer.domElement.style.margin = '0 auto';
renderer.domElement.style.display = 'block';
renderer.domElement.style.backgroundColor = '#dddddd';
$(document.body).append(renderer.domElement);
function update(){
renderer.render( scene, camera );
requestAnimationFrame( update );
}
update();
mtl_loader = new THREE.MTLLoader();
mtl_loader.load("assets/doughnut.mtl",
function(materials) {
materials.preload()
var obj_loader = new THREE.OBJLoader();
obj_loader.setMaterials(materials)
obj_loader.load("assets/doughnut.obj",
function(object) {
let mesh = object.children[0]
scene.add(mesh);
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
);
I have collada model (.dae) displayed by this code, and I add THREE.DoubleSide but it dose not work how can i fix this?
var loadingManager = new THREE.LoadingManager( function() {
scene.add( car );
} );
var loader = new THREE.ColladaLoader( loadingManager );
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('./model/car_Red.jpg');
loader.options.convertUpAxis = true;
loader.load( './car.dae', function ( collada ) {
car = collada.scene;
car.traverse(function (node) {
if (node.isMesh)
{
node.material.map = texture;
node.material.side = THREE.DoubleSide;
}
});
console.log(car);
I imported the 3D model that contains .obj .mtl and bunch of jpeg and pngs
trying to load the model with /images like this
But, I'm getting is only a black model like his
I wonder what I have missed as I followed the guidelines for using the two loaders.
here is my code.
//loader
var MTTLoader = new THREE.MTLLoader();
MTTLoader.setPath( '/assets/HotAirBalloonIridesium/' );
MTTLoader.load('Air_Balloon.mtl',(materials) => {
console.log(materials);
materials.preload()
var objLoader = new THREE.OBJLoader();
objLoader.load('/assets/HotAirBalloonIridesium/Air_Balloon.obj', (object) => {
console.log(materials)
objLoader.setMaterials(materials)
scene.add(object);
})
})
I wonder what i'm missing as my asset folder contains all the model files
try loading obj using
var loader = new THREE.OBJLoader( manager );
loader.load( 's_v1.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh )
{
// child.material.map = texture2;
// child.material.specularMap=texture;
// child.material.map=texture;
}
} );
// object.position.x = - 60;
// object.rotation.x = 0; //20* Math.PI / 180;
// object.rotation.z = 0;//20* Math.PI / 180;
object.scale.x = 80;
object.scale.y = 80;
object.scale.z = 80;
obj = object
scene.add( obj );
animate(obj);
} );
okay quick update, there was nothing wrong with the loader but I was using the wrong lighting as Phong Material needed
var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.50);
var dirLight = new THREE.DirectionalLight(0xffffff, 0.50);
to be apparent.
You must call "setMaterials" before load obj.
//loader
var MTTLoader = new THREE.MTLLoader();
MTTLoader.setPath( '/assets/HotAirBalloonIridesium/' );
MTTLoader.load('Air_Balloon.mtl',(materials) => {
console.log(materials);
materials.preload()
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials); // "setMaterials" must before "load"
objLoader.load('/assets/HotAirBalloonIridesium/Air_Balloon.obj', (object) => {
console.log(materials)
scene.add(object);
})
})
i'm trying to map a png file on mtl,obj file
Before mapping
but after mapping, the mtl texture just disappear.
After mapping
what should I do ?
I'm not good at English. If you can't understand my question, please leave a comment.
this is my code :
var onProgress = function(xhr) {
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 loader = new THREE.ImageLoader();
loader.load("../img/ang.png", function(image) {
texture.minFilter = THREE.LinearFilter;
texture.image = image;
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;
texture.offset.set(-3, -9.5);
texture.repeat.set(13, 13);
texture.needsUpdate = true;
},onProgress,onError);
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath('../models/');
mtlLoader.load('nag-green.mtl', function(materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('../models/');
objLoader.load('nag-green.obj', function(object) {
object.traverse(function(child) {
if (child instanceof THREE.Mesh) {
child.material.map = texture;
}
});
object.name = "object";
object.position.y = 0;
scene.add(object);
}, onProgress, onError);
});
what I want to do is to map 'ang.png' file over that t-shirts like this
what i want
Thank you for your answer Radio, I tried that way but this is not what i want to do.
give a name to material and map
You've applied the same 'ang.png' texture to all child meshes. I think you need a conditional in the traverse function to apply the texture only to the part of the mesh that needs the texture.
The mtl should have applied a name to the material when it first loaded. For example, here I am pretending the material name is "torso". Your exporter from the original 3d editor will have given it some other name. In any case, you should be able to query the name in the conditional:
object.traverse(function(child) {
if (child instanceof THREE.Mesh) {
if(child.material != undefined){
if(child.material.name=="torso"){
child.material.map = texture;
}
}
}
});