Modify gltf in runtime,fallback for textures

Hi all, I’m quite new to Babylon world.
I need to modify the GLTF viewer of vscode to do something custom.

The first problem I have is with textures
I would like to define a set of fallback folder

BABYLON.GLTFFileLoader.IncrementalLoading = false;
BABYLON.SceneLoader.AppendAsync(rootPath, 'data:' + gltfContent, scene, undefined, '.gltf').then(function () {
            scene.createDefaultCameraOrLight(true);
            scene.activeCamera.attachControl(canvas);
            scene.activeCamera.wheelDeltaPercentage = 0.005;

Practically I don’t want to modify the gltf but intercept his loading and eventually look in some fallback folder for textures…How can I do this?
I do not know enough the API , so I’m struggling a little bit
thanks

Reading at the source code, it seems there’s no way to easily intercept the loading path of textures.
The code in _loadTextureAsync is:

        if (image.uri) {
            if (Tools.IsBase64(image.uri)) {
                url = image.uri;
            }
            else if (this._babylonScene.getEngine().textureFormatInUse) {
                // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
                url = this._rootUrl + image.uri;
            }
        }

As you can see, the image.uri is concatened with this._rootUrl.

You could write a GLTF extension and override _loadTextureAsync, but it may not work because you need to access private members of the GLTF loader (at least I tried and it didn’t work because of that)…

yeah not so easy, I ended up modifying the exporter to do what I wanted to do

Now I have another problem
Any idea why a uri like this:

“uri”: “…%2Ftexture%2Fchecker-map_tho.png”

is parsed and correctly displayed in tree.js and not on babylon.js?

thanks

Do you have an error message in the console log? Is it a “not found” / 404 or a security error message?

the error I have is with the babylon engine in vscode
this is what he say
/images/0/uri: ‘…/texture/checker-map_tho.png’ is invalid
with tree.js engine the texture is visible without problem.
seems like babylon is not able to navigate on top of the gltf itself

so I found how to inject my resolved path
in the gltfPreview.ts file

I’m doing something like this

const gltfContent = gltfEditor.document.getText();
        var gltfAltered = JSON.parse(gltfContent);
        gltfAltered.images.forEach(element =>
            {
                console.log(element['uri']);
                var newPath = path.resolve(gltfFilePath, element['uri']);
                console.log('filepath' + newPath);
                element['uri'] = newPath;
            });

babylon engine does not allow any of this
neither an absolute path neither a relative path that go up in folder hierarchy
is there any way to avoid override this?

1 Like

pinging @bghgary to see how we can solve that

just to give a little bit of context
when artist export 2 gltf that share a common textures
for optimization they should point to the same texture

Also I do not understand why a gltf with a broken texture path should not be visible at all .
it should fallback in a default texture or something similar
Is this a missing feature or it is like this by design?

There are a couple of issues in question here:

  1. The glTF loader does not support absolute urls.
  2. The glTF loader rejects relative urls that have .. in them.

For context, here is what the spec says. If you want to see the initial discussion, see https://github.com/KhronosGroup/glTF/pull/1100#issuecomment-330332174.

The first is the result of only implementing support for relative paths. The second resulted from a security review. Both of these are security risks if the glTF is from untrusted sources.

As for your scenario, I’m assuming your glTF are from trusted sources, I think we can add a flag to turn off the .. check and possibly another flag for allowing additional url schemes (like http://). If you want either of these, please file issue(s) on GitHub.

Another related feature of the loader is the preprocessUrlAsync callback on the glTF loader that allows you to modify the url before the loader loads it. This currently happens after the .. check though.

I agree and I understand the security issues.
And of course leave this security check optional is the best solution in my opinion
Thanks, I will raise the issues on github

2 Likes

I’m doing the exact same thing for loading varying-texture GLTFs into Unity (where the additional textures are not predefined in the .gltf). I’ve tried injecting reference to new image at several places in the unity importer, and it always comes out fail in some way or other. Better to just change the JSON and reload from scratch. Good to see the method confirmed here.

There’s a fairly easy way to fix this using a GLTF extension.

In the extension constructor, you can do:

constructor(
    public loader: GLTFLoader,
  ) {
    this.loader.gltf.images?.forEach(image => {
       image.uri = `http://example.com/myimage.png`;
    }
 }

FWIW, I just tried this, and it doesn’t work, because the URI needs to be relative.

So if your asset was loaded from https://mywebsite/assets/model.gltf this would update the uri of the image to https://mywebsite/assets/http://example.com/myimage.png

It also doesn’t let you use ../ in the relative path, so right now I can’t see anyway to share textures between multiple gltf files if those textures are in a higher directory path than the models.

For example if I have two models that share the same texture:
/models/category1/model1.gltf
/models/category2/model2.gltf

They can’t share a texture in a “global” pool of textures at something like:
/textures/texture.png

Because there is no way to relatively get that texture path without using ../. Is that correct? Is there any way around this, or is it basically a limitation of the gltf spec?

Hi Tim, this definitely works and we’re using it in production. I’m not sure what’s different, but we are only loading in a single GLTF file and each texture path is updated to point to a service instead of the relative path. You can pass in params to the GLTF extensions, so you could include a prop that tells your various GLTF files which path to use based on some criteria. In my experience, the GLTF extension is very flexible and we’re using several of them to do various transformations to the data.

So I must be misunderstanding something then.

Take a look at this playground, and open up the developer console so you can see the error:

https://playground.babylonjs.com/#A8D6BB

How is that different than what you were doing above?