Using basis texture in react three fiber

I wanna use basis texture in my react three fiber app but it throwing an error. Here is demo of my code, I tried both native three js loader and r3f useLoader approach but both are throwing an error

function Plane() {
  const gl = useThree((state) => state.gl)
  const texture = useLoader(BasisTextureLoader, 'file.basis', (loader) => {
    loader.setTranscoderPath('/basis/')
    loader.detectSupport(gl)
  })
  return (
    <mesh>
      <meshBasicMaterial map={texture} />

the problem was that A. you didn’t include the transcoder and B. the loader is a little weird and you can’t omit ‘/’ in certain places. you can absolutely use useEffect and do it like in plain threejs as you did in your box, i would recommend useLoader though because now you have suspense integration.

1 Like

Thank you so much :slight_smile:

G’day Paul, is the Universal Basis loader the reason why that simple sandbox has a remarkably large js heap as seen in this screenshot?

I’m finding that in one of my projects that uses Basis, I’m also seeing a very large memory footprint that gets bigger and bigger the more the user engages with the page - note that this isn’t the case when using three.js’ standard TextureLoader and only happens with Basis. Stats are like: 13mb per page with TextureLoader vs 110mb that keeps growing with BasisLoader.

Just curious if this is a bug, GC issue or if it’s something to do with how the codesandbox is importing the transcoder? Cheers :slight_smile:

Saw something like this recently (Compressed textures using more memory than uncompressed textures? - #5 by donmccurdy) where the basis transcoder was reloaded many times, and also appears to be using R3F… in case it’s relevant!

1 Like

Hey Don, yeah looks to be the case but unsure if there’s a solution there? What would be causing the transcoder to be loaded multiple times in the sandbox?

I don’t really know how React and useLoader work enough to answer that, but this could happen if more than one BasisTextureLoader instance gets constructed. There’s a similar known issue for DRACOLoader on iOS; in the abstract it shouldn’t matter whether you construct multiple loader instances but in practice it currently does… I would like to fix that, sharing a WorkerPool instance regardless of how many loaders there are, at some point.

useLoader just calls new THREE.Loader().load(url, set)

i dont see it load the transcoder multiple times, looks like codesandbox redirects

as for heap snapshots in dev mode and codesandbox, i don’t know how relevant they are. csb does a lot of stuff in the background, i think they patch code as well to avoid infinite loops. react dev mode also has extra code for debug and profiling.

1 Like

I think I should try same scenario with native three js and react three fiber and compare the results, that might help us to know where the issue is probably. And if issue arises in both approaches then I’m the one who is doing it in a wrong way.

Curious to see how you get on, let us know please :slight_smile:

@drcmda your demo is not working

Could not load canestra_di_frutta_caravaggio.basis: undefined

i must have deleted the texture, assets weigh down on my codesandbox paid plan. the code would work though.

I’d love to see it working…

One more question, I’m just playing with the basisu cli tool and it does support mipmap encoding in the .basis or .ktx2 file. I want to know that does threejs know how to choose mipmap order from it to maximise performance or threejs creates its own like for jpg or png.

I recommend generating mipmaps offline like this if the texture will be shown in a 3D scene. three.js will use them correctly. It isn’t possible to generate mipmaps at runtime for compressed texture formats, as we would with PNG or JPEG.

1 Like

Thanks, seems like finally it could solve my major pain problem.