Relative/absolute paths to texture images

Thanks! Your comment pointed me in the direction of a hacky monkey patch that gets things working for me. I do think we could perhaps either improve the docs or add some support for this. This is my understanding:

According to the glTF spec a .glb file can contain resources (texture images) - these can be either Base64 encoded URIs, or relative or absolute URLs to the resource file.

For security/privacy reasons, BabylonJS only supports URIs below the rootUrl of the file being loaded. Absolute and relative URIs are not supported.

Given a file at https://example.com/3D/models/model.glb

...
images: [
  {
    name: 'copper_wires',
    mimeType: 'image/jpeg',
    uri: 'textures/copper_wires.jpg' 
  },
]
...

:white_check_mark: this works

...
images: [
  {
    name: 'copper_wires',
    mimeType: 'image/jpeg',
    uri: '../textures/copper_wires.jpg' 
  },
]
...

:x: This fails with an invalid URL error

...
images: [
  {
    name: 'copper_wires',
    mimeType: 'image/jpeg',
    uri: 'https://example.com/textures/copper_wires.jpg' 
  },
]
...

:x: This attempts to fetch the file at https://example.com/models/https://example.com/textures/copper_wires.jpg
and fails.

I have got this working with a ludicrously hacky solution that rewrites the URLs in the loader:

const loader = BABYLON.SceneLoader.Append("/3D/models", "model.glb", this.scene, (s) => {
  // Do something with loaded scene  
})! as any;

  
// Once the JSON in the loaded file has been parsed, rewrite the relative URLs to 
// something that will pass Babylon's URL validation and can later be intercepted 
// by the below preprocessUrlAsync function.
loader.onParsed = (data:{json:{images:{uri:string}[]}}) => {
  data.json.images = data.json.images.map( (image) => {
    return {
      ...image,
      uri: `${image.uri.replace('../../textures','//3D/textures')}`,
    }
  });
}

// Before loading a resource, take the previously rewritten URL that Babylon 
// is requesting and rewrite it.
loader.preprocessUrlAsync = (url:string):Promise<string> => {
  return Promise.resolve(`${url.split('//')[1]}`);
}

2 Likes