Load multiple gltf-files

Hi! I have 5631 glb-files on my server, which i load using gltf-loader. But google chrome throws an error: net::ERR_INSUFFICIENT_RESOURCES, and Firefox load, but i have 2 fps maybe.

How can load multiple glb’s, so that they don’t lag. I also use draco-compressor, but it doesn’t really help .

1 Like

Hello @ThisIsBacya
you can load multiple glb files using this code.
const glbFiles= useGLTF([“/models/model.glb”, “/models/model1.glb”]);
console.log("glbFiles: ", glbFiles);

But I have 5631 files and write each one to an array?
And my glb-models are stored in a database, therefore when i connected to db, i get all of these and put them on server

Are you loading 5361 files at the once?

Yes, because all of them are part of 1 big model

I think that you can use useGLTF(array).
Another method you should join all model in blender.

1 Like

But what is useGLTF? Node.js module or something other?

Loading 5000 glTF models simultaneously is far, far too many. Even if each model were well-optimized. But Draco compression will not make this any better, just compressing the filesize is very different than optimizing a model for runtime performance. It all still needs to be decompressed for rendering, and then you still have, at minimum, 5000 draw calls. Typical recommendation is to target <100 draw calls.

I would look for ways to reduce or merge the models, and then optimize what is left. If you’re not sure how to do that, it might help to share more detail about your goals for the project.

1 Like

I am developing 3d-viewer for BIM-models and 5000 files it’s just test project. Other models have 16k gltf-files or maybe even more. And i understand that if test project has about 20 FPS, other project will have 3 FPS or even less.

Hi @donmccurdy!
Can i use gltf-transform from you to merge files from database or no?

glTF Transform can be used (either as a CLI or a JavaScript library) to merge any number of glTF files/scenes, yes.

async function getModelsData() {
    try {
        const pool = await sql.connect(dbConfig);

        const result = await pool.request().query('SELECT gltfBinary FROM gltfData;');
        // console.log(result);
        
        return result.recordset.map(record => record.gltfData);
    }
    catch (error) {
        console.error('Error: ', error);
        throw error;
    }
}

async function mergeGllf() {
    try {
        const models = await getModelsData();

        const io = new NodeIO();

        if (models.length === 0) {
            throw new Error('Cannot find models');
        }

        const documents = await Promise.all(models.map( async (model)  => {
            const doc = await io.readBinary(new Uint8Array(model));
            return doc;
        }));

        let mergedDocument = documents[1];
        

        for (let i = 1; i < documents.length; i++) {
            mergedDocument = mergeDocuments(mergedDocument, documents[i]);

        }

        const mergedBuffer = io.writeBinary(mergedDocument);

        if(!mergedDocument){
            throw new Error('Cannot merge documents');
        }

        
        return mergedBuffer;
        
    } catch (error) {
        console.error("Error:",error)
    }
}

app.get('/merged-model', async (req, res) => {
    try {
        const mergedGlB = await mergeGllf();
        if (!mergedGlB){
            return res.status(500).json({ error: 'No data' });
        }
        res.setHeader('Content-Type', 'model/gltf-binary');
        res.send(Buffer.from(mergedGlB));
    } catch (error) {
        console.error('Ошибка:', error);
        res.status(500).json({ error: 'Error.', details: error.message });
    }
});

I try to merge models, but get error:
Error: TypeError: doc.getRoot is not a function
at NodeIO.writeJSON (C:\newFolder\3d-viewer\node_modules@gltf-transform\core\dist\index.cjs:6112:57)
at NodeIO.writeBinary (C:\newFolder\3d-viewer\node_modules@gltf-transform\core\dist\index.cjs:6133:37)
at mergeGllf (C:\newFolder\3d-viewer\src\express\server.js:106:33)
at runNextTicks (node:internal/process/task_queues:60:5)
at process.processImmediate (node:internal/timers:454:9)
at async C:\newFolder\3d-viewer\src\express\server.js:161:27

The code looks valid to me. If you’re sure everything in that documents array is a Document (no nulls?) then I might need some way to reproduce this (should be possible without Express or a DB?) to know what is wrong.

One guess, though… commonly dual package hazard is a problem in Node.js, and making sure to use either CJS or ESM consistently might avoid it if that’s the cause here.

I’m sure. All models from db not nulls.
And i’m use only commonjs modules:

const express = require('express');

const cors = require('cors');

const sql = require('mssql/msnodesqlv8.js');

const {mergeDocuments} = require('@gltf-transform/functions');

const {NodeIO} = require('@gltf-transform/core');

I see. The mergeDocuments() function does not return a document, it instead modifies the first document passed. To write a GLB you may also need to unpartition() the buffers. So usage in the loop could look like this:

import { unpartition, mergeDocuments } from '@gltf-transform/functions';

const targetDocument = documents.pop();

for (const sourceDocument of documents) {
  mergeDocuments(targetDocument, sourceDocument);
}

await targetDocument.transform(unpartition());

const mergedBuffer = await io.writeBinary(targetDocument);
3 Likes

Ty, it’s works!

wathe…, of course you can load 5361 but you must using promise and it need times