Importing gltf ArrayBuffers from loaders.gl

HI All,

I’m trying to use the 3D Tile loader from loaders.gl with Babylon.

Each tile is parsed using the gltf-loader which can serve either a post-processed json or glft array buffer.

I am able to parse the array buffer using:

function meshTileToMesh(tile: Tile3D, scene: Scene) {
    const arrayBuffer = tile.content.gltf.buffers[0].arrayBuffer;

    const file = new File([arrayBuffer], "test.gltf")

    const gltfFileLoader = new GLTFFileLoader()
    gltfFileLoader.loadFile(scene, file, (gltf) => {
        console.log(gltf);
    }, (error) => {
        console.log("progress")
    }, true);
}

Which I thought would append the meshes to the scene but this does not appear to be the case.

I can’t seem to get the SceneLoader to accept the arrayBuffer as it fails to parse.

Any guidance would be much appreciated.

  let file = new File([buffer], 'file.glb');
  SceneLoader.LoadAssetContainer(
      'file:',
      file
      ...

Hmm not sure if this is much help but I am able to load buffers this way ( need to add them to scene after with asset container )

Would you be able to reproduce that on the playground? Would be great to see what you are doing so we can help with that.

Pinging @bghgary just in case :slight_smile:

GLTFFileLoader isn’t meant to be used directly. GLTFFileLoader.loadFile is a hidden method used by the SceneLoader.

Based on the code snippet, it seems like you might be trying to load a gltf as a binary buffer? If so, you should convert it to a string and load it with as a string. Loading with a binary buffer is only for glb files.

@br-matt and @bghgary thanks for the tips!

RaananW I’m not sure how to minimally mock loaders.gl to post in the playground.

Using this:

const arrayBuffer = tile.content.gltfArrayBuffer;
const file = new File([arrayBuffer], "test.glb");
SceneLoader.LoadAssetContainer(
            'file:',
            file,
            this.scene,
            (container) => {
                const mesh = container.meshes[0];
                console.log('mesh', mesh);
            }
        );

I get the following error:
Unable to load from file:test.glb: /meshes/0/primitives/0: Mode 5 is not currently supported

So at least it is parsing.

I’ll try changing my Cesium Tileset to something that does not contain mode 5’s.

I’ll try changing my Cesium Tileset to something that does not contain mode 5’s.

From a quick glance that means maybe changing from triangle strip to triangle ?

It appears you are using Draco compressed glb with triangle strips. This is currently not implemented in the code. We can probably add it. Feel free to file a feature request on GitHub.

2 Likes

Hello. Sorry for reviving a year-old topic, but I can’t find anything more recent on this subject.

I was intrigued to find this conversation about using the 3D Tile loader with Babylon. I’m very new to Babylon (started reading about it yesterday) but it seems like it’s the right tool for what I’ve been asked to try to implement. Our company produces models in “3D Tiles format (.tls)” - so I am told - from its drone-based surveying of territory for local government agencies. So I think we would be looking to host the 3D model files (.tls - or should we be looking to export them into some other format?) on our web server and then load them into a new Babylon component, which I would build in to our existing 2D mapping Angular app.

If I’ve understood the issues correctly, the key challenge is to ensure that only the needed tiles are loaded to display the model as the camera is moved around within the space. Is that something that the loaders.gl 3D Tile loader takes care of, or is that a part that still needs to be solved? Presumably any event involving movement or re-orientation of the camera should trigger a reassessment of which tiles are needed and these should then be loaded / made available to Babylon. In the various code snippets I’ve seen here and elsewhere, I can’t see any sign of that kind of decision-making happening. What am I missing?

Am I even close to the mark with this, or should I start a completely separate topic? Is there any progress in your work, @Sam_Thomas, that would be relevant for this, or is anyone aware of any other progress being made on this concept? And, my final question(s): where should I go from here, and what can I do to assist you or others in helping me do what I need to do?

Thanks in advance!

This is my code, although not perfect, it can load 3tiles. It should be noted that postProcess: false


async loadModel() {
const tileUrl = ‘/tiles/tileset.json’;
const tilesetJson = await load(tileUrl, Tiles3DLoader);
const tileset3d = new Tileset3D(tilesetJson, {
// onTileLoad: tile => console.log(tile, 99)
});
const loaderTiles = async (modelList) => {
if (Array.isArray(modelList)) {
for (let item of modelList) {
if (item?.contentUrl) {
let tiles = await load(item.contentUrl, Tiles3DLoader, { decompress: true, gltf: { postProcess: false, decompressMeshes: false }, })
if (tiles.type === “cmpt”) {
for (let t of tiles.tiles) {
await this.loadGltf(t.gltf)
}
} else if (tiles.type === “b3dm”) {
await this.loadGltf(tiles.gltf)
}
//Other formats such as i3dm are loaded using the same method,
}
if (Array.isArray(item?.children)) {
loaderTiles(item?.children)
}
}
}

    }

    loaderTiles(tileset3d.root.children)

}
async loadGltf(gltf) {
    try {
        const file = new File([gltf.buffers[0].arrayBuffer], "file.glb");
        await BABYLON.SceneLoader.AppendAsync("file:", file, this.scene, (e) => { }, ".glb")
        this.engine.hideLoadingUI()
    } catch (error) {
        console.log(error)
    }

}

}

Thanks for the code; I’ll try it out some time soon. Any explanation you can supply of how it addresses these issues, and what is dealt with elsewhere, would be really interesting and helpful too! Much appreciated. :slight_smile: