Three.js materialLoader doesn't load embedded texture image - javascript

I'm exporting a three.js material using material.toJSON() provided method, this is the result:
{
"metadata":{"version":4.5,"type":"Material","generator":"Material.toJSON"},
"uuid":"8E6F9A32-1952-4E12-A099-632637DBD732",
"type":"MeshStandardMaterial",
"color":11141120,
"roughness":1,
"metalness":0.5,
"emissive":0,
"map":"876D3309-43AD-4EEE-946F-A8AE8BA53C9E",
"transparent":true,"depthFunc":3,"depthTest":true,"depthWrite":true,
"textures":[
{
"uuid":"876D3309-43AD-4EEE-946F-A8AE8BA53C9E",
"name":"",
"mapping":300,
"repeat":[1,1],
"offset":[0,0],
"center":[0,0],
"rotation":0,
"wrap":[1001,1001],
"minFilter":1008,
"magFilter":1006,
"anisotropy":1,
"flipY":true,
"image":"C6B4FEDA-8E7E-490A-A1AD-866ECE36E952"}],
"images":[
{
"uuid":"C6B4FEDA-8E7E-490A-A1AD-866ECE36E952",
"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAEACAYAAADFkM5nAAAg[...]"
}]}
I try to use MaterialLoader as the example suggest
https://threejs.org/docs/#api/loaders/MaterialLoader
but at parsing time I always get this error
THREE.MaterialLoader: Undefined texture
876D3309-43AD-4EEE-946F-A8AE8BA53C9E
I'm I wrong if I expect from the MaterialLoader to use the embedded resources?
I'm doing it wrong or missing something?
How can I also load the images in the json file into the related texture?
Thanks!
here a fiddle:
http://jsfiddle.net/akmcv7Lh/211/

Notice that MaterialLoader is not able to load textures. It expects that textures are set via MaterialLoader.setTextures() before loading a JSON file like ObjectLoader does:
const loader = new MaterialLoader();
loader.setTextures( textures );
So MaterialLoader can only be used as a standalone loader if the respective materials have no textures. Otherwise you have to prepare the textures on app level similar how ObjectLoader does.

Related

three.js load glb warning 'format' is not a property of this material

three.js is throwing three.module.js:7950 THREE.MeshStandardMaterial: 'format' is not a property of this material. when I load a .glb I made in blender.
Everything else works as expected. What dose this error mean? could it be that some property of my material I set in blender is not supported by threejs?
const loader = new GLTFLoader();
loader.load( '/myguy.glb', function ( gltf ) {
scene.add(gltf.scene);
const myguyMesh = gltf.scene.children.find((child) => child.name === "Human_Mesh");
}, undefined, function ( error ) {
console.error( error );
} );
i found this https://threejs.org/docs/#api/en/materials/Material
.format : Number
When this property is set to THREE.RGBFormat, the material is considered to be opaque and alpha values are ignored. Default is THREE.RGBAFormat.
but I don't really know where to go from here.
edit: i sort of know where to go from here.
there is some irrelevant(ish) glb property of my materials that is not accepted by three
I actually had the same problem as you! The first problem I can think of for it is that you had a texture for the object, and the code is trying to access it but can't get it, perhaps since it is in a different folder, etc. Another possibility is that the code is trying to access the texture through files that changed when exported. Good luck! -Codeitfast
mismatch between GLTFLoader version and three, I had a old three.js version, after updating it stopped

How to combine .gltf file with other assets; bin and png files for use in babylonjs

I feel like I'm close but still missing something. Here's what I have so far
var files = window.files;
console.log(files) // => (3) [File, File, File]
// File objects:
// 0: File {correctName: 'test.bin', name: 'test.bin' …}
// 1: File {correctName: 'test.gltf', name: 'test.gltf', …}
// 2: File {correctName: 'test.png', name: 'teest.png', …}
var fi = new BABYLON.FilesInput(engine, scene, (s) => {
console.log('here in scene loaded callback');
})
fi.loadFiles({ dataTransfer: { files: asheFiles } });
The scene loaded callback never gets called however. I also don't see anything being rendered on the canvas element in the page.
I know there's clearly a way to do it based on the example they have here:
https://sandbox.babylonjs.com/
I'm just trying to figure out how to recreate that.
Okay folks, I do have a solution.
Overview
After searching through many of their documentation pages, forums online and similar questions here on Stackoverflow, I've realized that Babylon js doesn't really sport a direct file load API. They have functions that can take file objects as arguments, but ultimately that does not meet the needs of digesting a gltf file that's split up into various parts, namely .gltf, .png, and .bin. As using a provided method such as BABYLON.SceneLoader.Append on the gltf file will fail once BABYLON parses it and immediately starts requesting the accompanying files (.png and .bin) over the web. Here you could theoretically use a .glb file, but that's not the file format I'm using in my project.
You need to hack the library into allowing you to do what you need. I started looking at the example code used in the linked sandbox above. They use this FileInput class to somehow load all the accompanying files together after a drag and drop event. I emulated the drag and drop functionality via:
function sceneLoadedCB(newScene) { window.scene = newSene; initCamera(newScene, canvas); }
const fi = new BABYLON.FilesInput(engine, scene, sceneLoadedCB)
fi.loadFiles({
dataTransfer: { files: [gltfFileObject, pngFileObject, binFileObject] }
})
This would've been good enough for my purposes except that it will always create another scene object in place of the current one, stopping me from loading up a scene with multiple gltf objects. Asset containers will not work to solve this as they are always bound to the scene they are created with; you cannot transfer assets from one scene to another.
The solution
I didn't reverse engineer the logic that parses and groups the files as all being part of the same gltf object. But I did find this static property of the FilesInputStore class being used as a place to store actual javascript File objects. If you populate this store with your gltf file accompanying file assets you will be able to load them together as all being part of your gltf file.
Demo:
var theScene // your babylon scene instance
const renderLoop = (sceneToRender) => {
sceneToRender = sceneToRender || window.scene
sceneToRender.render();
sceneToRender.getEngine().runRenderLoop(renderLoop);
};
yourGLTFFiles.forEach((file) => {
window.BABYLON.FilesInputStore.FilesToLoad[file.name] = file
})
const gltfFile = yourGLTFFiles.find((file) => file.name.includes('gltf'))
BABYLON.SceneLoader.Append('file:', gltfFile, theScene, function (loadedScene) {
console.log('here in scene loaded callback, scene: ', loadedScene)
// below will be true since append adds to the scene instance you passed it
console.log(loadedScene === theScene)
renderLoop(theScene)
});
This took me forever to solve. I hope this solution saves you time in building your awesome project!

Three.js texture is not loading - what would cause this?

I am trying to create a scene using .obj and .mtl files exported from blender. The object is literally just a rectangle (it needs to be a .obj file. more objects will be added to create a scene) I am able to see the material load, but cannot see the texture being applied in chrome or firefox.
the mtl file text
the obj file text
Here is the javascript code:
const obj_loader = new THREE.OBJLoader(),
mtl_loader = new THREE.MTLLoader();
// uses example of OBJ + MTL from three.js/examples
mtl_loader
.setTexturePath('bar/')
.setPath('bar/')
.load('floor.mtl', (materials) => {
materials.preload()
obj_loader
.setMaterials(materials)
setPath('bar/')
.load('floor.obj', (object) => {
// everything returns status 200!
// material is being applied but no texture
scene.add(object);
})
});
project file structure
Checking the console, requests for the mtl, obj, and image files are returning 200 status codes
but the model renders without texture
No errors are in the console at all. What would cause this issue in Three.js? I suspect something is wrong with the .obj or .mtl but I cannot find the problem. (the file paths are correct based on the logged ajax request).
This may be due to the .preload() method not being called on the materials object returned in the material load callback. The preload() method basically creates the material objects loaded by the MTLLoader.
Consider the following updates, with this method call added:
const mtl_loader = new THREE.MTLLoader();
mtl_loader.setTexturePath('bar/');
mtl_loader.setPath('bar/');
mtl_loader.load('floor.mtl', function(materials) {
// Add this (see link below for more detail)
materials.preload()
const obj_loader = new THREE.OBJLoader();
obj_loader.setMaterials(materials);
obj_loader.setPath('bar/');
obj_loader.load('floor.obj', function(object) {
scene.add(object);
})
});
Here is a link to the THREE source code which shows the inner workings of .preload() - hope this helps!
It turned out to be an issue with the UV mapping of the texture. In Blender, you can create a texture, and Blender will show the texture in 'render' mode, even if the UV map is not set (It will wrap automatically).
Blender showing render, even without UV Map
This was especially frustrating because I had these settings when exporting the file:
export settings for OBJ
The MTL and OBJ file appeared to have all the content in it, but by manually UV mapping the texture (instead of using a simple repeat in the "texture" menu) the issue was resolved when I exported again.
UV/Image editor needed to be used
Sorry for any confusion that may have caused. I hope it helps anyone who has the same issue exporting from Blender.

Multiple material on single obj file with three.js

I'm using three.js to load an obj file, a ring with some pearls. I haven't got an mtl file, as the software we use to export the obj (rhinoceros(?)) won't generate it with an obj file (this is what I was told by the graphic designer).
I need to set a metallic material ONLY for the ring, and glass material ONLY for the stone/pearls.
This is a link to the test page where I actually load the file:
jaaxlab.com/test_youring
...for the rest I don't know how to set a single material and also multiple.
Link to obj file jaaxlab.com/test_youring/obj/prova1.obj
Your object has several children. The child with index 0 is the ring. Also, its name is sezione_B_misura13_Riviera_mix_full anello_sezione_B_misura13.
So, you can access it like:
obj.children[0].material = new THREE.MeshStandardMaterial(...);
or
obj.getObjectByName('sezione_B_misura13_Riviera_mix_full anello_sezione_B_misura13').material = new THREE.MeshStandardMaterial(...);
Given that obj is the object, loaded with you loader.
Take a look at this jsfiddle. Load your file, then check the console log. You can also click any part of the object and see its id and name in the console.

Three.js loaded .obj does not show after updated to r67

My initial version of three.js is r62, and I can load and show my .obj Objects with .mtl file to the scene correctly.
However, after updating the three.js to r67 (with the OBJMTL loader), my object become unable to render on the scene. I tried to revert everything as the same as the code inside example in webgl_loader_obj_mtl.html from the official:
var loader = new THREE.OBJMTLLoader();
//The exmaple object
//loader.load( 'obj/male02/male02.obj', 'obj/male02/male02_dds.mtl'
//My object
loader.load( '../../my_model/my_model.obj"
, "../../my_model/my_model.mtl"
,function(object){
object.position.y = - 80;
scene.add( object );
}
);
It comes very wield that the example object comes from webgl_loader_obj_mtl.html can be loaded and showed in r67. But for my .obj file, the chrome console message shows that the files are successfully loaded, but it does not show up on the scene.
What would be the problem here? Does there are any limitation/format differences between r62 and r67 in importing .obj and .mtl files?
Looking forward for help, many thanks!

Categories

Resources