GLFT with Basis Universal texture in Three.js: Is mipmap required? - three.js

I change a PNG texture of a GLTF file to Basis Universal and try to read it through the GLTFLoader of Three.js.
I use basisu executale from https://github.com/BinomialLLC/basis_universal.
Loading a texture which was converted using -mipmap option of basisu executable is successful. The textures looks well.
But when a GLTF file with a basis texture which was converted without -mipmap option is loaded, it looks all black. I would like to load also texture not having mipmap.
Am I missing something? Or is mipmap required to load Basis texture in Three.js ?
I learned how to use BasisTextureLoader and GLTFLoader from Three.js documents. And my initialize code is like the attached code.
https://threejs.org/docs/?=GLTF#examples/en/loaders/GLTFLoader
https://threejs.org/docs/#examples/en/loaders/BasisTextureLoader
let basisLoader = new BasisTextureLoader()
.setTranscoderPath('examples/js/libs/basis/');
.detectSupport(viewer.renderer);
THREE.DefaultLoadingManager.addHandler(/\.basis$/i, basisLoader);
let dracoLoader = new DRACOLoader().setDecoderPath( 'examples/js/libs/libs/draco/' );
let gltfLoader = new GLTFLoader()
.setCrossOrigin('anonymous')
.setDRACOLoader( dracoLoader );

To use Basis Universal compression in a glTF file, don't use the .basis format or BasisTextureLoader – the standardized way to do that is with a .ktx2 file. There's an artist guide for updating a glTF asset to use .ktx2 textures available, which includes some details on mipmaps. You'll almost always need mipmaps, unless you know enough about mipmap filtering to be sure you can disable it without causing rendering issues (this is rare).
three.js provides an example of how to load these files, which would look something like this:
const ktx2Loader = new KTX2Loader()
.setTranscoderPath( 'path/to/basis/transcoder/' )
.detectSupport( renderer );
const loader = new GLTFLoader();
loader.setKTX2Loader( ktx2Loader );
loader.load( 'path/to/model.glb', function ( gltf ) {
...
}, undefined, console.error );

Related

JeelizFaceFilter and THREEJS issue with gltf and texture models

Goal
I'm stuck since yesterday with an issue on modifying a JeelizFilterFace example. My goal is to create my own filters, so I started the the luffy's hat tutorial, which explains that : https://jeeliz.com/blog/creating-a-snapchat-like-filter-with-jeelizs-facefilter-api-part-1-creating-your-first-filter/
Quick description of the problem
My problem is simple : I can't have the glTF example working with glTF models. It always show me a black shape, without the texture.
Details of the problem
The tutorial explains that the model have to be generated with a Blender exporter addons, in order to create the json file which is the model. But the Blender exporter is not supported anymore.
This is why I try to use ThreeJS with the GLTF loader (which is the best solution according to all the tutorials).
My problem is that I can't see any texture on any of my models, when I load it with JeelizFaceFilter/Threejs. I only have the black shape.
Here is what I did :
First, I did all the tutorial to be sure I can run the FilterFace tool, except for the exporting model from Blender part. So, I just copied the exported resources from the Jeeliz repo. The FilterFace works well : the hat is visible, with the texture and I can play with the THREEJS params.
Because I couldn't export the JSON from blender, i wanted to try to use the GLTF 2.0 model, I tried this model, which is working in the gltf-viewer tool (see picture below) : https://s3.eu-west-3.amazonaws.com/com.julianlecalvez/LuffysHat.zip
So far everything seems ok, but when I try to use this glTF loader example in the glTF demos (https://github.com/jeeliz/jeelizFaceFilter/tree/master/demos/threejs/gltf_fullScreen), it displays my hat in black. I have the good shape, but no texture (or no light?). I just replaced the model URL in this file. And I'm not even sure that the default model (the helmet) is displaying any texture.
I tried with a model from SketchFab, and I have the same : Black shape, no texture.
I put here the code to init the view, when I was trying to redo it outside of the demo file :
let init_view = function(spec) {
const threeStuffs = THREE.JeelizHelper.init(spec, null);
const SETTINGS = {
gltfModelURL: 'objects/luffys_hat_gltf/luffys_hat.gltf',
offsetYZ: [1,0],
scale: 2.2
};
// const loader = new THREE.GLTFLoader();
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load( SETTINGS.gltfModelURL, function ( gltf ) {
gltf.scene.frustumCulled = false;
// center and scale the object:
const bbox = new THREE.Box3().expandByObject(gltf.scene);
// center the model:
const centerBBox = bbox.getCenter(new THREE.Vector3());
gltf.scene.position.add(centerBBox.multiplyScalar(-1));
gltf.scene.position.add(new THREE.Vector3(0,SETTINGS.offsetYZ[0], SETTINGS.offsetYZ[1]));
// scale the model according to its width:
const sizeX = bbox.getSize(new THREE.Vector3()).x;
gltf.scene.scale.multiplyScalar(SETTINGS.scale / sizeX);
// dispatch the model:
threeStuffs.faceObject.add(gltf.scene);
});
// CREATE THE CAMERA
THREECAMERA = THREE.JeelizHelper.create_camera();
}

Aframe Load lightmap after loading GLTF - lightmap not showing

I'm trying to add a lightmap to some mesh after loading them from a GLTF file.
All my objects have 2UV channel.
I'm waiting 'object3dset' and here is my code :
const mesh = this.el.getObject3D('mesh');
var textureLoader = new THREE.TextureLoader();
textureLoader.load("lightmap.png", function(lmap){
mesh.traverse((node) => {
if (!node.isMesh) return;
node.material.lightMap = lmap;
lmap.flipY = node.material.map.flipY; //needed to flip the texture
node.material.needsUpdate = true;
});
});
If I replace the material with a new one and set the lightmap, it's working.
But I want to find a way without recreating all materials.
The lightmap was loaded, but not easy to see.
By default metalness from Khronos Blender Exporter converted in threejs after loading GLTF result to a level 1.0. With this configuration, the lightmap is hard to see and is not corresponding to what we see in Blender.
I hope my mistake can help someone else losing too much time.

How do I change the texture of a GLTF model dynamically?

In my scene I have loaded a .gltf model and it is rendered just fine.. It has a .png texture that is rendered on the surface of the 3d model. Is it possible to swap the texture programmatically? I'm using aframe (a-asset-item and a-entity to load the gltf asset)
Once you’ve loaded a model in A-Frame or three.js, it doesn’t matter much what format it was before1. For A-Frame, you can use JS to modify the model after it loads.
var tex = new THREE.TextureLoader().load('diffuse.png');
tex.flipY = false; // for glTF models.
el.addEventListener('model-loaded', function (e {
e.detail.model.traverse(function(node) {
if (node.isMesh) node.material.map = tex;
});
});
See docs on THREE.MeshStandardMaterial to learn what properties there are to edit, although this could vary depending on the model you’re loading.
1 One exception is the tex.flipY=false setting above — you'll (probably) only need that for glTF, where the UVs have a different orientation than the three.js default.

How can I add textures to collada file (.dae) using THREE.js?

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.

Loading multiple objects in Three.js from Blender

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 :)

Resources