pmndrs / drei

🥉 useful helpers for react-three-fiber
https://docs.pmnd.rs/drei
MIT License
8.42k stars 708 forks source link

useTexture crashes if image is not valid #1882

Open stingray21 opened 8 months ago

stingray21 commented 8 months ago

Problem description:

I'm using @react-three/fiber's useTexture to generate a decal for a three.js object.

The url for the image file (fileName) gets generated dynamically and the image files live on a different server

This works fine as long as the file exists. However, I get a runtime error, if the file is not valid.

Unhandled Runtime Error
Error: Could not load https://example.com/files/image: undefined

I cannot figure out how to catch/mitigate that error.

Relevant code:

decal = useTexture(fileName)

Here is a minimal working code sample: https://codesandbox.io/p/sandbox/adoring-dijkstra-mz2hsy

Suggested solution:

I already tried to wrap it in a try/catch

  let decal = {}
  try {
    decal = useTexture(fileName)
  } catch (error) {
    console.log('Could not load texture', fileName)
  }

but that never loads the decal, even if the image file exists and causes a never ending amount of this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'elements')
    at Matrix3.copy (three.module.js:1425:22)
    at refreshTransformUniform (three.module.js:17783:23)
    at refreshUniformsCommon (three.module.js:17847:13)
    at Object.refreshMaterialUniforms (three.module.js:17806:13)
    at setProgram (three.module.js:19469:27)
    at WebGLRenderer.renderBufferDirect (three.module.js:18762:29)
    at renderObject (three.module.js:19201:23)
    at renderObjects (three.module.js:19183:21)
    at renderScene (three.module.js:19101:48)
    at WebGLRenderer.render (three.module.js:19005:17)
    at render$1 (index-8afac004.esm.js:1506:63)
    at loop (index-8afac004.esm.js:1528:27)
    at sentryWrapped (helpers.js:80:23)

And this version (using an empty image in catch)

  let decal = {}
  try {
    decal = useTexture(fileName)
  } catch (error) {
    console.log('Could not load texture', fileName)
decal = useTexture('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=')
  }

causes this error:

Unhandled Runtime Error
Error: Should have a queue. This is likely a bug in React. Please file an issue.

Seems like this drei issue is related, but I couldn't fix my problem that way (ErrorBoundary) either.

When I use TextureLoader instead of useTexture, i.e.

// decal = useTexture(fileName)
decal = new THREE.TextureLoader().load(fileName)

then there is just no texture with the faulty url and I get this error in the console:

console.js:43 THREE.WebGLRenderer: Texture marked for update but no image data found.

but the site does not crash completely.

nikolajbech commented 6 months ago

A library like this might help: https://github.com/bvaughn/react-error-boundary

zrooda commented 2 months ago

You can't put hooks in try/catch blocks (https://github.com/facebook/react/issues/16026) so I wouldn't expect useTexture to do anything about that, but as ^ implied you can catch it with ErrorBoundary (nice lib here) and attempt to pass a fallback texture or do whatever else you imagined inside catch before resetting the EB render.

github-actions[bot] commented 4 days ago

Thank you for contributing! We’re marking this issue as stale as a gentle reminder to revisit it and give it the attention it needs to move forward.

Any activity, like adding an update or comment, will automatically remove the stale label so it stays on our radar.

Feel free to reach out on Discord if you need support or feedback from the community. This issue will close automatically soon if there’s no further activity. Thank you for understanding and for being part of the project!