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'
},
]
...
this works
...
images: [
{
name: 'copper_wires',
mimeType: 'image/jpeg',
uri: '../textures/copper_wires.jpg'
},
]
...
This fails with an invalid URL error
...
images: [
{
name: 'copper_wires',
mimeType: 'image/jpeg',
uri: 'https://example.com/textures/copper_wires.jpg'
},
]
...
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]}`);
}