Search code examples
compressionmeshgltfbabylonjs

Error while loading Draco-compressed mesh (glTF-Transform) in BabylonJS


I am trying to load Draco-compressed meshes, processed server-side with glTF-Transform, in BabylonJS retrieving them on the fly via REST calls. Due to this, the mesh to load doesn’t have an extension, because it is a blob in memory and the method URL.createObjectURL() (which is being used to have a URL for such blob) doesn’t allow to specify an extension or a custom URL. If one tries to import the blob as it is, SceneLoader.ImportMeshAsync() seems to not know how to load it and gives

createModelRenderable.ts:520 Error during loading meshes, try again RuntimeError: Unable to load from blob:http://127.0.0.1:5173/b3b55baa-4ede-41fd-a66e-304460969a7f: importMesh of undefined from undefined version: undefined, exporter version: undefinedimportMesh has failed JSON parse
    at A (sceneLoader.js:343:46)
    at Object.importMesh (babylonFileLoader.js:797:17)
    at sceneLoader.js:382:35
    at A (sceneLoader.js:182:13)
    at fileTools.js:375:9
    at XMLHttpRequest.A (fileTools.js:489:33)

without being even able to load a classic .glb. That’s why you have to specify “.glb” as the pluginExtension parameter of ImportMeshAsync to make it work. By doing so, the classic glb will load, but the draco-compressed one won't because (maybe? I suppose) its schema definition doesn't specify any extension mesh.primitive.KHR_draco_mesh_compression.schema.json

createModelRenderable.ts:519 Error during loading meshes, try again RuntimeError: Unable to load from blob:http://127.0.0.1:5173/07f9e64c-2c58-4c64-81c0-54f7d3bbb586: (this.dracoCompression || E8.Default)._decodeMeshToGeometryForGltfAsync is not a function
    at A (sceneLoader.js:343:46)
    at sceneLoader.js:397:21

By the way, the KHR_draco_mesh_compression is loaded because trying to add it again will raise a warning saying that “there’s no need to add the KHR_draco_mesh_compression extension because it’s already present”. I have already checked that draco’s configuration was ok, and the default one points to a valid CDN

wasmUrl: “https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js”
wasmBinaryUrl: “https://preview.babylonjs.com/draco_decoder_gltf.wasm”
fallbackUrl: “https://preview.babylonjs.com/draco_decoder_gltf.js”

the decoder wasm is downloaded correctly. I have anyway tried to use local files, but the result was the same.

I'm also sure that the mesh is a valid Draco compressed GLB file, because it loads correctly on https://sandbox.babylonjs.com/

I also tried loading the mesh as a file with something classic like

const loadFileAsync = function (url) {
  return new Promise(function (resolve, reject) {
    LoadFile(
      url,
      function (data) {
        resolve(data);
      },
      undefined,
      undefined,
      true,
      function (_request, exception) {
        reject(exception);
      }
    );
  });
};

and then decode its Draco-compressed part with new DracoCompression().decodeMeshAsync() to mix it then with texture and the rest but no luck again getting "Not a Draco file." in response.

Seems the same issue is faced in this post on BabylonJS forum, still without any working solution.


Solution

  • After debugging BabylonJS' core I discovered that using “.glb” was right and it was using the correct loader (glTFLoader), but there was a version mismatch in babylon’s imports causing a function not to be found, namely, _decodeMeshToGeometryForGltfAsync()