Different file formats and engines have different conventions for UV coordinates. In glTF files, the UV coordinates are defined such that:
…the texture coordinate value of (0.0, 0.0) points to the beginning of the first (upper-left) image pixel, while the texture coordinate value of (1.0, 1.0) points to the end of the last (lower-right) image pixel.
In three.js this would imply that your THREE.Texture should be configured with the texture.flipY = false setting, the default is true. Other 3D model formats may have other conventions, or none specified. GLTFLoader handles this automatically if the texture is referenced by the .gltf/.glb file, but when manually adding a texture to a mesh from a glTF file, you’ll need to set .flipY=false yourself. Whether ZIMjs has any additional requirements, I’m not sure.
An alternative to texture.flipY would be to flip the texture coordinates on the geometry after loading, instead. If you prefer that approach, see:
Note: I made it also with the threejs robot https://threejs.org/examples/#webgl_animation_skinning_morph where there was no texture problem because it is colored?
Lots of links there – sorry, that’s more than I’m going to click through! If you want to create one minimal reproducible example with a model and a texture not working as expected, I could try looking at that. If the issue is only happening in ZIM apps, it might be worth asking on the ZIM forums as well. I don’t have experience with ZIM myself.
Setting a breakpoint in the GLTFLoader source of the ZIM app, we see this error in the console:
THREE.GLTFLoader: Couldn’t load texture
TypeError: Failed to execute ‘createObjectURL’ on ‘URL’: Overload resolution failed.
Adding a breakpoint near the source of that error, execution fails on the following lines:
// Load binary image data from bufferView, if provided.
sourceURI = parser.getDependency( 'bufferView', sourceDef.bufferView ).then( function ( bufferView ) {
isObjectURL = true;
const blob = new Blob( [ bufferView ], { type: sourceDef.mimeType } );
sourceURI = URL.createObjectURL( blob ); // ‼️
return sourceURI;
} );
It looks like the ZIM environment has replaced the global Blob class with something else. Typing Blob in the console and you’ll see that it prints a different constructor than the usual [ native code ] result you’d get on other websites. So, it looks like this is a bug with the ZIM environment and would need to be reported there.
One option to work around the issue might be to use .gltf files with external textures, rather than .glb files with embedded textures, but normally in three.js that would not be needed.
it works perfectly with .gltf files, so that is why is wondering if it was a ThreeJS problem or ZIMjs problem, @danzen told it was a ThreeJS problem.. ok so thanks for your answers. I’ll check it out.
at the start of the ready event before bringing in the three.js model.
If you then need a ZIM Blob too use zim.Blob.
We had made and used a ZIM Blob for a few years before we realized that JS had a Blob too. So the solution above should work. You can also set zns=true in a JS script before importing ZIM to force the zim namespace and then if you want globals use zimplify(“Blob”); which will exclude Blob from globals.