Textures in gLTF sometimes display black, but only on iOS

I use ImageLoader to manage textures manully so it’s easily to wrap a setTimeout to each image request. If you use loaders such as gltf loader, I’m not sure how to control the texture loading frequency.

Understood… Unfortunately in my case i don’t have access to the textures as a saparate object but i receive a glb with textures already built in.
Thank you anyway

Hello @aidenhjj

I’m trying to follow your steps (but in angular) but i get the error DataCloneError: The object can not be cloned when the code hit the load function
Here is my code

 const texLoader = new KTX2Loader();
    const texLoadManager = new LoadingManager();
    texLoadManager.addHandler(/\.ktx2$/, texLoader);
    const loader = new GLTFLoader(texLoadManager)
    texLoader.setTranscoderPath("assets/three/basis/");
    texLoader.detectSupport(this.renderer);
    loader
      .load("assets/lenses/test.gltf", gltf => {
        console.log('x', gltf)
      })

Do you have any idea what could cause this?
This is the gltf folder
Schermata 2021-11-23 alle 16.01.17

@tomthebearded - I’m not sure. I’ve not seen this error. Have you tested just fetching the basis/ files and the gltf files? I wonder if the filename links to the textures in the gltf file got corrupted somehow.

Thank you for the quick response… i’ve update the threejs version and now when the code reaches the load function it doesn’t seem to do anything.
I’ll try to re-create the gltf with the basis tool.

Ok now i can load the model but the texture are missing
For some reason it’s searching files with a duplicate extension .ktx2.ktx2. I don’t know why, if i inspect the gltf there is only one ktx2 per file.

The gltf file has a json component - you should be able to just open it in a text editor and search for those file names - it looks to me that you’ve mangled the fillenames in the gltf itself.

Checked it, there aren’t files with .ktx2.ktx2 extension.
It’s very frustrating. I’ve just tried another method i found new GLTFLoader().setKTX2Loader(texLoader) but this doesn’t find the files even if the extension is correct.
@Mugen87 i’m calling for your help.

It seems like your glTF files are corrupted somehow – do they work in online viewers? The steps here would be how I’d recommend creating glTF files with KTX2/Basis textures:

1 Like

You are right, i’ve tried an online viewer and textures aren’t loaded right… i’m gonna try your steps
Thank you

We’ve had this black textures issue bugging our app on iOS since version 14 and it does seem indeed that the issue is now appearing much more frequently on iOS 15.

I was tasked to find the root cause of the issue and I pinpointed it to image bitmaps. On iOS 14 and 15 all textures that use image bitmaps as the image are sometimes displayed as fully black, and this happens very often on iOS 15.

So a quick fix is to just not use image bitmaps on iOS. Since you can’t disable the usage of image bitmaps in GLTFLoader via any options (three.js/GLTFLoader.js at 00a692864f541a3ec194d266e220efd597eb28fa · mrdoob/three.js · GitHub), I used this (a bit hacky) little piece of code in our app, which effectively disables the usage of image bitmaps on iOS:

const IS_IOS =
  /^(iPad|iPhone|iPod)/.test(window.navigator.platform) ||
  (/^Mac/.test(window.navigator.platform) && window.navigator.maxTouchPoints > 1);
if (IS_IOS) {
  window.createImageBitmap = undefined;
}

And finally to prove my point that the issue is indeed in image bitmaps, here’s a test scene that has 15 planes with 2048x2048 textures.

On my iPhone 7 (iOS 15.1) the ImageLoader version never shows any black textures, but the ImageBitmapLoader version does render some (4-6 of them) of the textures black 90% of the time.

This is definitely something that should be fixed by Apple and a webkit bug report ought to be submitted, but in the mean time I also wonder if this is something that should be handled inside GLTFLoader? What do you think @donmccurdy?

3 Likes

Many thanks for that workaround! This problem also exists on iPads running iOS 15 and your little hack also fixes this issues for the iPad.

Does anyone know if there are any side effects to do

window.createImageBitmap = undefined;

for every device (not just iOS/iPad OS)?

Thank you @donmccurdy i followed your steps and the issue is at least mitigated, unfortunately if a user switch quickly models many time some times the black textures appear again and after a while the app reloads… but my client’s users shouldn’t use the app in that way. And also my client doesn’t want a temporary lock from one switch to another.
For now i’ll keep everything like this hoping that apple will release a fix soon.

Thanks @niklasramo! The results of the CodeSandbox are, interestingly, very consistent for me – exactly 10 images load, and any additional images appear as black squares.

That seems like a strong sign that Safari has some kind of memory limit here, and any ImageBitmap textures exceeding that limit are rejected. Another interesting point is that if I add this line to the THREE.ImageBitmapLoader configuration…

const loader = new ImageBitmapLoader()
loader.setOptions({
  imageOrientation: 'flipY',
  resizeWidth: 512,
  resizeHeight: 512
})

…it’ll consistently load all of the textures every time on my iPhone.

Based on all that, I’d be fine with adding an option in GLTFLoader to disable the ImageBitmapLoader use, but I wouldn’t want to do it automatically – we don’t really know if the application is going to hit this memory limit in advance, and if it doesn’t then the performance benefits are probably worthwhile. I think it’d be worthwhile to report this to Apple, if only to find out exactly what is happening.

1 Like

Is Apple aware of this? They really should fix this.

I’m having the same problem here with GLB models in A-Frame, the problem appears only in iOS…

This webkit ticket seems to be related, based on Kimmo Kinnunen’s comment: 232357 – Huge textures are not rendered correctly

Most likely this has to do with ImageBitmaps being resident in the Web process and GPUP or Web process running out of memory.
Symptoms are typically:

  • black texture
  • GPUP crash via Jetsam.
  • GPUP crash via resource limit hit during memmove inside CG, probably when overcommitted allocation requests pages and fails

Thanks, all this was useful. I got many reports and just tested with safari 15.2.1, still have the problem with this version.
The workaround from @niklasramo seems to work, thank you

Do we know if this is still an ongoing issue? im just wondering if i still need to disable this function for ios

If you look at the webkit ticket you’ll see it’s still open, nothing has been answered, and last time I checked it was still problematic

1 Like