sceneLoadedCallback scene parameter usage

I will start by giving some context: I want to share a model via socket.io.
My model can be composed as follow:

  • 1 mtl file
  • 1 obj file.
  • several jpgs images being the textures

I was wondering if the scene: Scene parameter created in the sceneLoadedCallback of the FilesInput class contains the data of the obj+mtl+jpgs therefore I don’t need to broadcast all these files to all the clients.
OR
If I still need to broadcast these files because the Scene object is actually just using these jpegs + mtl+ obj files: my idea was to use JSZip to compress all the files in one document then broadcast it via the sever and then unzip it on every client side.

FilesInput(engine: Engine, scene: Nullable<Scene>, sceneLoadedCallback: Nullable<(sceneFile: File, scene: Scene) => void>,...

Just to clarify my question, let’s say my model have
JPEG texture (xx KB of data)
Obj file (yy KB of data)
Mtl file (zz KB of data)
Is the xx + yy + zz data present in the resulting Scene parameter in the sceneLoadedCallback?

Thank you for your help

Yes, the scene will contain the meshes + materials (+textures) created by reading the obj / mtl / jpeg files if that is your question. Note that this scene is the one you passed to the constructor of FilesInput.

Note also that the files themselves are not present per see: it’s the result of their processing that’s there (meshes, materials, textures).

2 Likes

Thank your for your answer, that is what I want to replicate in every client browser. I just need the result of the processing not the actual files used to generate the model.
The problem I’m facing now is that I am unable to broadcast this object via socket.io. For some reason it can’t be created as a JSON because of circular reference. Do you know a way I can broadcast and then recreate the scene in the other clients session ?
Is sending the meshes,materials,textures of the scene as 3 separated JSON objects could work ?

Error when using JSON.stringify(scene) to broadcast the scene:

image

You won’t be able to directly send the scene object over the wire as there are too much dependencies / circular references, you should first serialize it with something like:

var serializedScene = BABYLON.SceneSerializer.Serialize(scene);
var strScene = JSON.stringify(serializedScene);

and send the string.

On the other side, load the data as a .babylon file with the scene loader.

1 Like

I’ve tried what you suggested, so the shape is broadcasted correctly but it seems that the textures are not. Below you can see on the right the view in the browser of the client that need to broadcast the model and on the left the one receiving it

And in the console I have errors saying
Local ressource not found File://texture1.jpg
Local ressource not found File://texture2.jpg
Local ressource not found File://texture3.jpg

To recreate the scene I’ve used the following line:
BABYLON.SceneLoader.Append('', 'data:' + newScene, this.scene, this.updateScene.bind(this), null , this.appendError.bind(this));

newScene being the serialized scene that is broadcasted through socket.io

When you said load the data as .babylon file what did you meant by this ?

I meant what you did, using the SceneLoader to parse the data.

Regarding the missing images, I thought it was possible to serialize a scene with the pictures embedded in, I think I have already seen .babylon files with embedded picture data but I don’t recall where / how those data were embedded. It’s also possible I’m wrong… Maybe others will know better.

[…] Maybe the data are embedded only when the urls you pass to the texture constructor are data urls…

Set the following global static to true, to serialize textures that were loaded from images :slight_smile: available in 4.2+

BABYLON.Texture.ForceSerializeBuffers = true;

1 Like

@aWeirdo I’m using Babylons 4.2.0-rc.6 and when I tried what you suggested the model is not loading even in the client who uploaded the model. I have this error

image

If I comment the line you suggested, it works in the local client.

I just saw that there is 4.2.0 that just got released, I’ll try to update and I’ll let you know. Thanks for your help

@Observablerxjs
that is weird!
it fetches pixel data directly from webgl/gpu so should work in any situation…
why a texture width would be 0 is odd

can you share your scene in any way?

Here is a link to the model I am loading in my app

I just updated to latest (4.2.0) and still the same error when using ForceSerializeBuffers

@aWeirdo If I comment the part where I serialize the scene it works

So the error comes when ForceSerializeBuffers is true and this serializing part as mentionned by @Evgeni_Popov is executed:
BABYLON.SceneSerializer.Serialize(babylonScene);

Do I need to set some attributes of the SceneSerializer to true when the BABYLON.Texture.ForceSerializeBuffers is set to true ?

You don’t have to set anything else, no.

it works for me… :slightly_frowning_face:

scene(4).babylon dragged directly into sandbox & light made from console

1 Like

Oh so you converted the obj model first to a .babylon file ?

Because on my side, I just drag and drop the 6 files in the canvas (the files in the google drive link I’ve sent you earlier).

Do I need to convert the obj first to a .babylon and then serialize it?

no no, the serializer creates a babylon file, you’re just passing it over socket.io as a string rather than in a name.babylon… both should work!

I don’t suppose you’re on mac/ios ?

No I’m on windows but does that make any difference? because ultimately the app I’m working on is supposed to run on IPad Pros.

just been a bunch of webgl bugs from apple lately, could maybe have explained it :slight_smile:

Hummm I just tried the exact same operations (with the exact same files) in the sandbox and it works, even the serialization. I’m not sure why though :confused: ?

As you can see below the base64string after the serialization

I managed to make it work finally :smiley:

The error was that the serialization was being executed before the scene was actually ready to be serialized. The solution was to place it inside a executeWhenReady block

onSceneLoaded(sceneFile: File, babylonScene: BABYLON.Scene)
{
   /*WRONG*/
   const serializedScene = BABYLON.SceneSerializer.Serialize(babylonScene);
  
   /*CORRECT*/
   babylonScene.executeWhenReady(() =>
   {
      const serializedScene = BABYLON.SceneSerializer.Serialize(babylonScene);
      const jsonObj = JSON.stringify(serializedScene);
      // broadcast object via socket.io here
    });
    .
    .
    .
}

Thank you again for your help @aWeirdo and @Evgeni_Popov

2 Likes