Reputation: 529
I am bringing in geometry and materials through a JSON file. For the most part, this works well, except now I am trying to also bring in textures maps. From what I can tell, the THREE.ObjectLoader strips out any image information from the loaded textures, and thus, the material does not have access to the image source. I've tried several things, but they all lead to the same result: if I recreate a material with a texture map and apply it to a loaded object, the object disappears.
In order to ensure that something would work, I created a simple scene with a cube and a material. This works just fine:
var textureDiff = THREE.ImageUtils.loadTexture( "img/brick_diffuse.jpg" );
textureDiff.wrapS = THREE.RepeatWrapping;
textureDiff.wrapT = THREE.RepeatWrapping;
textureDiff.repeat.set( 2, 2 );
var textureBump = THREE.ImageUtils.loadTexture( "img/brick_bump.jpg" );
textureBump.wrapS = THREE.RepeatWrapping;
textureBump.wrapT = THREE.RepeatWrapping;
textureBump.repeat.set( 2, 2 );
var material = new THREE.MeshPhongMaterial({map: textureDiff, bumpMap: textureBump});
var geometry = new THREE.BoxGeometry( 2, 2, 2 );
var cube = new THREE.Mesh( geometry, material );
cube.name = "myCube";
cube.position.set( 0, 1, 0 );
cube.castShadow = true;
cube.receiveShadow = true;
scene.add( cube );
I get a cube with the brick texture. Great! I can even mix the order of this, for example, add the cube with a simple material, add it to the scene, find the cube by its name, and replace it with a new material. All of that works.
Loading the objects through the THREE.ObjectLoader works at first glance. The objects are there and they have a material color indicative of the material they were assigned in the application which generated the JSON. If I interrogate an object loaded in this method, almost all of the characteristics that I expect and are stored in the file are there. But when I look at the object's material, the map slot is null. So I looked at the source for THREE.ObjectLoader and from that I gathered that maybe material textures maps are not loaded. The ObjectLoader defers to the MaterialLoader which seems to have no logic to deal with texture maps.
So, I tried to also process the materials from the parsed JSON scene object. Here I get the structure as I have it in my JSON file. I go through the materials, textures, and images and create a new array of materials from this. If I interrogate the new material array, the map contains a texture object with an image. I've tried to load the texture in several ways:
First, by using ImageUtils like in my test above:
scene.children[i].material.map = THREE.ImageUtils.loadTexture('img/brick_diffuse.jpg');
Second, by actually constructing everything, first loading the image, then making a texture, then making a material, and then applying this to the object (here is a the material construction code). In this case, if I remove the map, an imported object turns red:
var loaderImg = new THREE.ImageLoader();
// load a image resource
loaderImg.load( // resource URL
'img/brick_diffuse.jpg',
// Function when resource is loaded
function ( image ) { // do something with it // like drawing a part of it on a canvas
console.log("image loaded!");
texture = new THREE.Texture({
image : image,
wrapS : THREE.RepeatWrapping,
wrapT : THREE.RepeatWrapping,
repeat : [1,1]
});
material = new THREE.MeshPhongMaterial({
color: new THREE.Color('rgb(0,0,255)'),
map: texture
});
//add material to object
scene.children[i].material = material;
},
function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); },
// Function called when download errors
function ( xhr ) { console.log( 'An error happened' ); } );
I've tried many iterations of the above and all results point to the same result: if I add a map to the material I am created, the object does not appear, if I omit the map attribute of the material, the imported object changes material (new colors and other properties are seen).
I see a few roads here: 1. Just use the parsed JSON scene and forget about the THREE.ObjectLoader, iterating through all of the objects in the file, grabbing their associated material, etc, constructing it all bit by bit. 2. Extend THREE.MaterialLoader to go in and actually load images 3. Go a bit nuts.
I have seen several questions on here dealing with similar issues, yet there does not seem to be a clear response. I've also tried other methods suggested in some of the answers, I always get a missing object.
I am on threejs r70, have tried on local and remote servers, on Chrome and Firefox.
Finally, I tried these two things:
var textureDiff = THREE.ImageUtils.loadTexture( "img/Cork.png" );
textureDiff.wrapS = THREE.RepeatWrapping;
textureDiff.wrapT = THREE.RepeatWrapping;
textureDiff.repeat.set( 2, 2 );
var material = new THREE.MeshPhongMaterial({
color:new THREE.Color('rgb(255,0,0)'),
map: textureDiff
});
var geometry = new THREE.BoxGeometry( 2, 2, 2 );
var mmm = new THREE.Mesh(geometry, material );
scene.add(mmm);
2. Here, if instead I use the geometry of the imported object to make a new mesh, the mesh disappears:
var textureDiff = THREE.ImageUtils.loadTexture( "img/Cork.png" );
textureDiff.wrapS = THREE.RepeatWrapping;
textureDiff.wrapT = THREE.RepeatWrapping;
textureDiff.repeat.set( 2, 2 );
var geometry = new THREE.BoxGeometry( 2, 2, 2 );
var material = new THREE.MeshPhongMaterial({
color:new THREE.Color('rgb(255,0,0)'),
map: textureDiff
});
var mmm = new THREE.Mesh(scene.children[i].geometry, material );
scene.add(mmm);
If I do comment out the map (//map: textureDiff), the imported geometry is red, taking on the color of the material.
Apologies for the long query, I wanted to ensure I documented my attempts. I hope I am over complicating things, as I am surely missing a simple piece of information on why my objects disappear if I try to add a material with a texture. Thanks.
Upvotes: 1
Views: 4398
Reputation: 529
The issue I was dealing with had several sub issues related: 1. The THREE.ObjectLoader in r70 of threejs does not support material texture loading. 2. My JSON was did not include any face vertex uvs.
To solve the first issue, I looked through the source and through pull requests and found a modification to the object loader. since those changes were not compiled into the library, I built a mixed threejs, replacing the current revision ObjectLoader with the one in this pull request.
To solve the second issue, I added the mesh face vertex uvs from my application to the json file being written.
The pull request has now been merged with the dev branch of threejs.
Thanks to @denzp for the modification and for @mrdoob (and other contributors) for the great work on threejs.
Upvotes: 3