Sharing models via Socket.io

Hello, I have a Node.js on my backend and I’m using Socket.io for a real-time application.

My goal with my app is:
Let’s say we have 3 clients: A, B and C
When I upload my model (1 .obj, 1 .mtl, some .jpg textures) on client A I want it to be broadcasted to B and C. Also since clients B and C are iPads I don’t want to store the model locally then open it, I want to directly after sending the model to B and C feed them to babylon.js keeping them in the RAM of the iPad.

Did someone succeeded to achieve something similar?

Maybe we can send the model uploaded on client A to the server, and then have clients B and C fetch that model from the server


We can use WebSocket (Socket.io) to let the server broadcast a message to each client containing the URL to the model. This way, the client knows when and where to download the model from.

I’m not sure if sending large files over WebSocket (Socket.io) is ideal.

I think if the files do not have textures you can send the JSON via webSocket and then add them like this:

BABYLON.SceneLoader.ImportMesh("", ASSETS_URL, "data:" + jsonContent, scene, (    meshList, particleSystems, skeletons) => {
...
}

This is a special syntax that is not very well documented (it’s not really a data URL), but it works! We use a similar approach with very good results. I think the size of typical babylon (JSON) files won’t be a problem at all for the websocket server. This approach is good if you reuse the same textures anyways, but not so good if you need to send new textures, for the reason @gbz gave.

1 Like

I have a similar setup for my RTS game. I only use socket.io to broadcast small messages though. All models are downloaded seperately to each client prior to starting a game.

I think the solution posted by @gbz is a valid one for your scenario.

1 Like

The files does include textures for example it would be something like:

- MyObj.obj
- MyMaterial.mtl
- Text1.jpg
- Text2.jpg
- Text3.jpg

I was planning to use the assetsManager as assetsManager.addTextureTask for the textures files and assetsManager.addMeshTask for the .obj and the .mtl then call assetsManager.load() to load all my model. Do you think this is a good way to do that using socket.io and is that also possible using the JSON of each file with the assetsManager?

Also do you think that uploading my model on a github repo would be better to load the model? I would just give the url to each client instead of sending them the files.

Finally I forgot to precise: in my scenario, client A is on the Server (on a windows machine) and client B and C are iPads. So there is no need to first upload the files to the server as @gbz suggested the client who would broadcast the files is already on the server.

I have not read the whole thing, but would remind you that textures can be inside of .babylon file (base-64). The Blender export has that option, & possibly other exporters. Probably want to something like gzip though to get comparable transmission size.

They are also inside .glb files. When doing something like this, must easier to get everything in on transaction.

2 Likes

So you’re idea is to not send the model as separate files (like .obj,.mtl and .jpg) but instead broadcast one .babylon file via websockets to all the clients?
Because when I read the docs on the .babylon format, I saw that there is reference to the mesh/materials/textures files so I would still need to send those to all the clients?

EDIT
I just read this medium article: Exporting 3D content for Babylon.js - Babylon.js - Medium and I understood that I can put all my files in one .glb file. So final question? is there a good way of broadcasting this file to all my clients ?

I avoid doing the bulky processing by the server. I do all the processing by the client and send small data to the server (references or numbers) and send small data to the clients and the bulk is done by the client, which is necessarily more efficient.

This avoids overloading the server. Basically the server must receive and send the smallest possible of data to be reactive in real time, it avoids slowdown for the client who would all players impact. I saw players deserting from a game because of that.

1 Like

Thanks for your answer, my app is not a game actually I’m working on a 3D viewer. Also I don’t want to store the files on the client side I want only the server to have the files. Hence, I have to send the whole file to the clients (.glb or .babylon).
I have two options:

  • find a way to send the files via socket (that is actually my question)
  • store my model (.glb or .babylon) on github and make the client request the model and retrieve it from github using the method described here Using External Assets - Babylon.js Documentation.

I managed to find a way to send binary data from my server to the clients, here is what I have so far:

Server side:

/* example to send one .obj file, 
I repeat the same process with the other assets files*/
fs.readFile('./src/Files/object1.obj', (err,buff) => {
    if(err){
        console.error(err);
    }
    socket.emit("loadAsset", buff);
})

Client side:

const CHUNK_SIZE = 32768;
let idx = 0;
this.socket.on('loadAsset', (buff) => {
    const data = new Uint8Array(buff);
   // if .obj or .mtl
   // load obj with babylon ?
   // else if jpg or png do this
    const length = data.length;
    let slice;
    let res = '';
    while (idx < length) {
        slice = data.slice(idx, Math.min(idx + CHUNK_SIZE, length));
        res += String.fromCharCode.apply(null, slice);
        idx += CHUNK_SIZE;
    }
    /* res is the encoded base64 jpg img, I need to load this image as texture*/
});

So the part I still don’t know how to do is load my assets (.obj,.mtl or .jpg) with babylon now that I have the binary format of these files.

Hi @Observablerxjs,

Have you taken a look at this page

https://doc.babylonjs.com/how_to/load_from_any_file_type

Hi @Observablerxjs,

I was inspired by your use case and wrote this week’s demo to answer your question. Check it out!

4 Likes