Compressed Texture Workflow (glTF|Basis)

I’m hitting GPU Memory problems with my current workflow of using glTFs with jpg and png images on mobile. Sadly I can’t find a good setup to avoid that.

I guess the next step is to either use GPU compressed texture formats like basis or to reduce the texture resolution. Sadly I haven’t figured out a good workflow for rcreating and linking optimized assets.

My questions are:

  1. Is the basis texture format already a feasible format for all platforms?
  2. Is it possible to link basis textures in glTF files?
  3. What tools do you use to create optimized textures (with Mipmaps / Texture Atlases)?
  4. Is there a possibility to check the available GPU memory to load low res textures for mobile devices?
  5. Is there an ETA for including basis textures in glTFs?

Right now, we’re using Blender to export the glTF files, which only supports exporting jpegs and pngs.
I would love to hear from your workflows to optimize the textures and models for the web!

We tested basis textures and are really satisfied with the reduction in filesize. So far I encountered some problems with 8k textures on mobile (rendering just black), but Im unsure what the cause is.

To answer some of your questions:

I converted the blender output texture from png to basis using the supplied tool and replaced the texture slot in the gltf manually (editing code in the model file).

The officially supplied converter from basis universal team. Creating mipmaps for the textures increases conversion time and filesize by a noticeable amount, but I couldnt see a difference in Performance or visual representation.

To throw in some Numbers: In one case the filesize on 4k textures went from 13.9 MB JPG to 7.0 MB basis, and in another from 7.4 MB to 0.53 MB without mipmaps and very little loss of detail.

2 Likes

Hi @weiserhei,

thanks a lot for your insights! So I guess you’re using the custom GLTFLoader from the basis live demo example (https://basis-universal-webgl.now.sh/gltf/)?

As I understand there will be a ktx2 wrapper around basis files in glTF in the long run (https://www.khronos.org/assets/uploads/developers/library/2019-siggraph/glTF-Ecosystem-Forum-SIGGRAPH_Aug19.pdf). Is it worth waiting on that?

I see, so I might need to build a little automation tool.

That sounds really good! Thanks a lot lot for the real world dara comparison!

@weiserhei: I modified the gltf loader to support basis textures so done in https://github.com/BinomialLLC/basis_universal/tree/master/webgl/gltf.
I also got the provided model there to work. Sadly when I try to put the PavingStone example from ThreeJS on a simple cube, the cube stays black. Here is the file I’m working with: image_template.zip (526.9 KB)

I edited the texture to point to the basis texture:
“textures” : [
{
“source” : 0
}
],
“images” : [
{
“mimeType” : “image/basis”,
“name” : “d_image_template”,
“uri” : “PavingStones.basis”
}
],
“extensionsUsed”: [
“GOOGLE_texture_basis”
],
“extensionsRequired”: [
“GOOGLE_texture_basis”
],

Any idea what I’m missing?

Your images-part looks correct. Make sure to include the necessary lib files and that they are loaded which are required by basis.
I imported your files into my project and without modifying anything this is the result:

Thanks a lot for your test. That’s interesting.

I tried digging a bit further, the logic for calling BasisTextureLoader and loading the texture seems to be correct, strangly it just is not rendering.
I made a small repro: https://deml.io/three/examples/webgl_loader_gltf_basis.html


The front box is the one I uploaded here, which has the basis texture seemingly in the map property, but is not rendering it. The cube in the back is generated and the texture is set for the material manually, this one works as expected.

Forked repo:
glTF Loader | Html Repro file

Seems like you didn’t go down the road of using extensions. How did you change the loader to support basis textures?

I dont remember changing the loader, this Part should be running Out of the Box. I followed this article on medium: https://medium.com/samsung-internet-dev/using-basis-textures-in-three-js-6eb7e104447d

Edit: i would have to Check the source Control to actually verify my Statements, they are Just coming from my memory :smile:

Additionally I have compressed and converted my gltf-basis Models using DRACO, but this doesnt affect your Cube.
Im not using Extensions, These lines are Missing in my Models - do you mind Sharing some information about this?

Ah, I stumbled over that post a while ago. As far as I can tell, it’s only about loading the textures themselves (as in the BasisTexture Loader example I integrated in the reproduction, which actually works). I guess my question then is: How did you connect the BasisTextureLoader with your GLTFLoader?

I wanted to use the extension “GOOGLE_texture_basis”, which they also use in their example. It will most likely be replaced, but from what I can tell, this might be the standard right now. My idea was that the extesion can signal which textureloader should be used. The problem is, I can’t tell which step does not work, since at least the basis texture is loaded and some texture is in the map channel of the material, but it does not show in the renderer.

The link to enable basis textures happens via the loading Manager. I guess this part of code should be doing the job, but its just an extract from my project for the sake of simplicity.

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { BasisTextureLoader } from "three/examples/jsm/loaders/BasisTextureLoader.js";
[...]

const basisLoader = new BasisTextureLoader(loadingManager);
basisLoader.setTranscoderPath('libs/basis/');
basisLoader.detectSupport(renderer);
loadingManager.addHandler(/\.basis$/i, basisLoader);

const gltfLoader = new GLTFLoader(loadingManager);

Then proceed to load your model and add it to the scene.

It will definitely be replaced. :sweat_smile: I made it up to get a functional demo, but it’s not an official standard at all sorry! The real extensions are in progress.

Hm, I actually do that as well. I tried using the default loading manager like so:

var basisLoader = new BasisTextureLoader();
basisLoader.setTranscoderPath( 'js/libs/basis/' );
basisLoader.detectSupport( renderer );
THREE.DefaultLoadingManager.addHandler( /\.basis$/, basisLoader );

// model
var loader = new GLTFLoader().setPath( 'models/gltf/BasisBlock/glTF-basis/' );

I also tried creating an own loading manager:

var loadingManager = new THREE.LoadingManager();
var basisLoader = new BasisTextureLoader(loadingManager);
basisLoader.setTranscoderPath( 'js/libs/basis/' );
basisLoader.detectSupport( renderer );
loadingManager.addHandler( /\.basis$/, basisLoader );

// model
var loader = new GLTFLoader(loadingManager).setPath( 'models/gltf/BasisBlock/glTF-basis/' );

I also tried using the default GLTFLoader without the extension support, since that is what you seem to do. I can’t put my finger on what I’m missing here…

Yout stated that quite clearly in the code, no worries. Still, since there was a working example out there, it was the first point for me to look at to see how it is implemented. Maybe you are able to tell me why the basis texture is not rendering? I followed your example quite rigorously. You can find it over here: https://github.com/JohannesDeml/three.js/blob/b51acb0215998a7284d9a7f220733e361620b78e/examples/webgl_loader_gltf_basis.html

Sorry for the delay on this. If you set texture.minFilter = texture.maxFilter = THREE.LinearFilter you’ll see the texture:

Those settings should probably be in the glTF file itself, as a sampler for the texture, but without an official extension it’s pretty DIY at the moment.

1 Like

Aha! Thanks so much for the info. I somehow missed that in all the threads I read. Perfect, the example now works for me, finally I can join the basis party :partying_face:

1 Like