SceneImporter not loading MeshFaceMaterial textures in r68 - three.js

I have a scene which I am exporting from Blender using the Three.js exporter. After a bit of trial and error I got it to export fine. When I tried to import it into Three, I got a few WebGL errors like glDrawElements: range out of bounds for buffer, which seemed to be related to the size or positioning of the imported object. I mucked around with some stuff related to size and eventually got it to load fine. However, none of my materials with textures are loading, EXCEPT one, which was an object with a single material applied to it.
Here's my pipeline
Create base for the level in my three js editor tool
Export this and import it into Blender for texturing/uv mapping (works fine)
Objects can have a number of materials, one for each face really, each material can have a different texture mapped to it (all good, objects are uv unwrapped etc..,)
Join all objects together (except one object which is a tree with a single material/texture applied to it)
Export the Blender file as a JSON file via the Three.js exporter
Load the file into Three using the SceneImporter
When it comes into Three, there are two objects, one is the tree which has a single texture mapped to its material. The other is a large geometry with 20 materials and textures mapped. This geometry does not have any textures displaying and just shows as a MeshLambertMaterial.
Has anyone else experienced any issues like this? Any solutions?

Seems like the SceneImporter doesn't know what to do with these materials, but all the data is there, so you'll need to give it a little help.
Like so;
loader.load('sceneWithObjectOfManyFaceMaterials.json' , function(loaded)
{
for(var key in loaded.objects)
{
var mesh = loaded.objects[key];
if(mesh.material.materials)
{
mesh.material.materials.forEach(function(m , i)
{
m.map = loaded.materials[m.name].map;
});
}
scene.add(mesh);
}
render();
});

Related

I can't get the aoMap showing in three.js using a glb/gltf asset

I’m having a hard time getting an aoMap working in three.js…
I have a glb asset with an aoMap on the red channel or something. When I bring it into to the babylon viewer, I can see the ao just fine, but it wont show up in the three.js viewer or my project. I think this has something to do with a second set of uvs, but I can't find a resource that involves doing that on top of using the gltf loader… I really don't know what to do here. Any response would be greatly appreciated!
Here is my code (I’m using a html-canvas as the texture)
And I get the model’s geometry and diffuse texture (all white) as desired, but the aomap isnt showing…
code
babylon viewer
three.js viewer
working application with shadows included in diffuse
not working, diffuse is just white, and aoMap is not showing
You're right about needing a second set of UVs. The reason behind this is that diffuse textures often repeat (think of a brick wall, or checkered t-shirt). AO shading, however, is more likely to be unique on each part of the geometry, so it's almost never repetitive. Since this often would need an alternative UV mapping method, the default is to use a second set of UVs.
You could do 2 things:
Re-export your GLTF asset with a duplicate set of UVs.
Duplicate existing UVs in Three.js by creating a new BufferAttribute in your geometry:
// Get existing `uv` data array
const uv1Array = mesh.geometry.getAttribute("uv").array;
// Use this array to create new attribute named `uv2`
mesh.geometry.setAttribute( 'uv2', new THREE.BufferAttribute( uv1Array, 2 ) );
.getAttribute and .setAttribute are methods of BufferGeometry, if you want to read more about them.

Three.js | applying texture from Blender model

I'm using a free 3d model from turbosquid. This model is using a texture that looks like this:
It does look good in Blender:
But once exported to three.js, it seems that the texture does not follow the uv map:
Here is the code i'm using:
var loader = new THREE.JSONLoader();
loader.load('json/Ship.json', function ( geometry, materials ) {
ship = new THREE.Mesh(geometry, materials[0]);
scene.add(ship);
}
);
And here is the json I get once exported from Blender:
What am I missing?
Thanks a lot for your help!
There are some minor complexities in this model, which I think are causing issues for Blender exporters. They're not "wrong", but they're hard for exporters to handle without cleanup. You can fix those manually (open the .blend file in Blender, apply modifiers, remove all textures except the diffuse) but the easiest path is probably converting the OBJ version provided by Turbosquid to glTF. Going to the Cesium OBJ->glTF converter (or OBJ2GLTF if you need something programmatic) and dragging in the OBJ/MTL/texture will give the right result. NOTE: you'll need to move the sh3.jpg file into the same directory as the MTL file; it shouldn't be in the Textures/ folder.
Result on https://gltf-viewer.donmccurdy.com/ — using three.js r92 and THREE.GLTFLoader.

exporting a scene from blender to threejs: every object has just one single material

I have made a small scene in blender (6 objects, each using 1 to 4 materials).
When exporting this (using the materials, and the scene option) with the dev exporter and loading it via:
var loader = new THREE.ObjectLoader();
loader.load( 'assets/scene.json', function ( scene ) { ...
And then checking the scene, I can see it has 6 children (good) and that each of the five children only has one MeshLambertMaterial (instead of the material mix from blender) bad.
Any hints on what I am doing wrong?
Those are btw basic materials (just a color basically) no textures or anything.
The scene renders correctly (minus the material mix).
Here is a link to the 113kb scene file (zipped): http://jppresents.net/static/blender/exportBug/scene.zip
Looking at the file I think all materials are there - so the problem must be the way I load it?
Not a solution, but a work around:
Since the only difference between all my materials was just the color, I have now applied exactly one material with a multi colored texture per object.
Then I uv-mapped the faces of the object to the colors corresponding to the previously set material color.
This was easy using the hotkey "shift + G" which lets you select all faces with the same material. (Then just assign them to the texture material, move/scale those in the uv-view to the part of the texture that matches the old color.)

Why do I need to update uvs?

I'm working with the three.js editor where I parse an object from JSON format. As usual it first parses the materials and geometries, then I create meshes from it. While parsing materials I also load textures. The issue now is that I have to call...
object.geometry.uvsNeedUpdate = true;
object.geometry.buffersNeedUpdate = true;
... after the image for the texture completely loaded - but why?! The geometry never changed before, neither did its uvs or anything like it. It's still the plain old geometry, yet I always get a GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2 when trying to render. It only works with this "hack" although the geometry is always the same.
In my opinion it should also work perfectly when I update the uvs after object creation (or not at all). I didn't find anything in the three.js editor code that would update the geometry or its faceVertexUvs.
I know it's a bit of an abstract problem, I'm mainly looking for some hints or insights why this hack might be necessary.
Thanks!
Three.js "guesses" whether uvs are needed according to your used textures in bufferGuessUVType. If you want to preallocate uv buffers you can either init a map attribute with an empty THREE.Texture, update the geometry after the map was assigned, etc.

importing google sketchup objects into threejs -- textures not being rendered

I'm creating a disc golf game for the browser. A friend of mine is assisting me by creating objects in Trimble Sketchup, so that I can import them into the game. He has exported a .dae file and the textures, and I have imported them using the ColladaLoader.js. The textures and object load, and the object is rendered, but the object is black, and, sometimes, the javascript console says some textures cannot be rendered.
Here is some code :
var loader = new THREE.ColladaLoader();
var dae;
loader.options.convertUpAxis = true;
loader.load( '/discgolf/static/models/BelmontDreamCourse.dae', function ( collada ) {
dae = collada.scene;
dae.scale.x = dae.scale.y = dae.scale.z = 2.0;
dae.position.set( 5, 5, 5 );
scene.add( dae );
} );
What else do I need to do? I will be happy to provide more information.
Without more information it's quite a quesswork, but I'd check three things first:
Make sure the texture path is correct (check Firebug Net panel or such for which path it's trying to load the textures). You might need to search & replace the texture path in the DAE, if I remember correctly SU can sometimes put absolute paths there.
Do you have lights in the scene? If I remember correctly, ColladaLoader converts the SU DAE materials to MeshPhongMaterial, which does need some lights to show up unlike MeshBasicMaterial.
Do you have an animation loop, so that the thing is constantly rendered? If not so, make sure that you re-render the scene not only after the model is loaded, but after the textures are loaded too (they are lazy loaded after the model).
Make sure to resize the texture files to power-of-two dimensions (256x512, 256x256,1024x1024 and so on). WebGL does not like arbitrarily sized textures.

Resources