4

We are trying to merge multiple GLTFs on server side and export the merged gltf as final result on server.

Things we have trued that worked and that didn't:

  1. We have used three js GLTFLoader parse method to load multiple gltf files, merge the parent and children of the loaded objects and export the final model using GLTFExporter.

  2. We have used jsdom to resolve the issues related to window, document etc.

  3. Above mentioned points work for gltfs without textures

  4. While Loading GLTF with textures the response gets stuck.

    a) We tried hosting the files on server and use the GLTFLoader load method with "localhost:******" as loader path.

    b) Internally TextureLoader invoked ImageLoader where the onLoad event was not getting triggered at all . May be jsdom was not invoking this.

    c) To solve this we changed ImageLoader to have canvas image :

        const { Image } = require("canvas");
        const image = new Image();
        image.onload = onImageLoad;
        image.onerror = onImageError;

d) The load method got resolved after above change.

e) Next step - Exporting the GLTF - We got stuck due to ImageData not found error. We added ImageData from canvas and the GLTF was exported.

f) The exported GLTF is not viewable die to corrupted data in images

 "images": [
    {
      "mimeType": "image/png",
      "uri": "data:,"
    }
  ],

If someone loaded and merged GLTfs with texture images purely server side, Please Help!

Nilu
  • 262
  • 1
  • 8

1 Answers1

7

As three.js is primarily a 3D rendering library for the web, and relies on various web image and WebGL APIs, I'm not sure using THREE.GLTFLoader is the most efficient way to merge glTF files on a Node.js server. I'd suggest this, instead:

import { Document, NodeIO } from '@gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '@gltf-transform/extensions';

const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);

const document = new Document();
const root = document.getRoot();

// Merge all files.
for (const path of filePaths) {
  document.merge(io.read(path));
}

// (Optional) Consolidate buffers.
const buffer = root.listBuffers()[0];
root.listAccessors().forEach((a) => a.setBuffer(buffer));
root.listBuffers().forEach((b, index) => index > 0 ? b.dispose() : null);

io.write('./output.glb', document);

It's worth noting that this process will result in a glTF file containing multiple separate scenes. If you want to combine them into a single scene, arranged in some way, you'd need to use the scene API to do that. If the files are not on disk, there are other NodeIO APIs for processing binary or JSON files in memory.

Don McCurdy
  • 10,975
  • 2
  • 37
  • 75
  • I was able to merge the children of the scenes to scene 0 and dispose off rest of the scenes. I am still facing some issues on the rendering of overriding materials, but this approach has definitely helped me move forward with this. Thanks a ton!! – Nilu Jun 21 '21 at 11:01