Serializing mesh in ES6 Module has many problems

Our goal is serializing a mesh, and use JSON.stringify() to covert it to string, and then we use SceneLoader.ImportMesh() to load the string data re-displaying the mesh.

note:
the argument sceneFilename is able to be parsed by starting with “data:” following by the stringified version of the scene or a File object (default: empty string),

Github repo: GitHub - hjlld/serializing-mesh-babylonjs-es6-moudle

  1. Because of all the js file inside the dist version of @babylonjs/core require an external module ‘ts-lib’, so they cannot be imported directly in browser in runtime. (But Why???) so i can’t realize it in the Playground, but i’ll give a minimum repository on Github.

  2. AbstractMesh.getPhysicsImpostor() is not defined in the class AbstractMesh but in the file babylon.physicsEngineComponent.ts, which is necessary for SceneSerializer.SerializeMesh(mesh). So if your scene doesn’t need physics but serializing meshes, you will get an error this.getPhysicsImpostor is not a function.

There is a TODO decorator in the source code, so temporarily we can do polyfill with:

// `mesh` is the mesh pending to serialize
mesh.__proto__.getPhysicsImpostor = function () {
    return this.physicsImpostor;
};
  1. When above done, then we’ll meet the next problem:
Uncaught TypeError: Cannot read property 'plugin' of undefined
    at Function.SceneLoader._loadData (sceneLoader.ts:364)

it seems like there’s no default plugin for loading a stringified data directly, because in the ES6 version, the default value of SceneLoader._registeredPlugins is an empty object.

But according to this tutorial, the result of SceneSerializer.Serialize() is actually the content of .babylon file which can be loaded by the plugin babylonFileLoader.

But which default plugin is for serialized mesh? let’s have a try:

import '@babylonjs/core/Loading/Plugins/babylonFileLoader'

then we get no errors, hoory!

=== EDIT ===

when we import stringfied data, we must not give the new mesh a name, we should always make the first argument meshNames as an empty string.

SceneLoader.ImportMesh('', '', `data:${JSON.stringify(obj)}`, scene)  //correct
SceneLoader.ImportMesh('mesh', '',`data:${JSON.stringify(obj)}`, scene)  //wrong

now we finaly kick our goal!

  1. some other suggestions:

① many classes do not have serialize method, and some other classes can be serialized but have no method for restoring or re-parsing to the original, it’s really rare. When we deal with web workers, or save content into IndexedDB, we really depend on the serialization feature.

② in umd mode, babylon.js is a great engine library, because it can guide the developers step by step to reach their goal. but in es6 module, developers have to looking for the right modules to import by reading the source code, which is really a puzzle slowing down the fast build. should we have a more detailed tutorial for es6 developers?

Pinging @sebavan for 1.

ES6 modules are more complicated than UMD for a good reason: we protect backward compatibility. Without it we would have change a lot of API to better adapt to ES6 build.

But as we do not want to break existing code we had to introduce side effects (ES6 - Babylon.js Documentation) like the problem you faced with physics.

I would highly suggest to do a PR to fix the serializer in this case. We could simply add a test before serializing physics so it will not break if physics was not imported. Do you want to do that PR or else create an issue so someone else can take of it?

mesh.serialize will return a json object that can then be directly stringified and reloaded later by SceneLoader. It is using babylonjs format so as you found out you need babylonFileLoader.

@Deltakosh , it finally works now. when i import mesh from stringfied data, i give the new mesh a name, which cause the problem of empty array, then i make the first argument meshNames as an empty string, it solves.:smiley:

SceneLoader.ImportMesh('', '', `data:${JSON.stringify(obj)}`, scene)  //correct
SceneLoader.ImportMesh('mesh', '', `data:${JSON.stringify(obj)}`, scene)  //wrong

I really understand the importance of compatibility and fully support this principal(in fact, it’s one of the biggest reason why i love babylon.js, unlike some other libraries create break changes like changing underwear everyday).

but should we provide a detailed guide for es6 developers? for example, if i don’t read carefully the page you mentioned , i will never find that scene.createDefaultCameraOrLight() is hidden in @babylonjs/core/Helpers/sceneHelpers. and there’re many other cases not listed in the page, like in my case need import not only SceneLoader but also babylonFileLoader.

Very minor, but obj could be big & you are using ES6. Doing the ‘+’ could be replaced with
data:${JSON.stringify(obj)}. Darn, nested back quotes do not show, but you should know what I mean.

I do not know that the impact on stack memory will be better by avoiding a copy, but I try do do this in all my code now. It really helps make the code more readable when things are more than the simple case here.

1 Like

Issue created:

Thank you, I have changed my code.

Yup I do agree having an enhanced guide would be cool. Do not hesitate to make a PR on the doc website for the missing parts.

About the point 1. it is to prevent Typescript to inject it in all the modules. This way the code is shared and it make the output smaller.

Github issue fixed :slight_smile: It will be in the next package.

1 Like