I’m facing a problem where, when trying to run SceneSerializer.Serialize(scene)
I’m sometimes getting the following error: Cannot read property 'length' of undefined at Mesh.push.wAMR.Mesh.serialize
(with certain imported models). I think I’m doing the required ES6 imports (using this post to double check: Serializing mesh in ES6 Module has many problems):
import { SceneSerializer } from '@babylonjs/core/Misc/sceneSerializer';
import '@babylonjs/core/Physics/physicsEngineComponent';
What confuses me even more is that I have some other models exported from the same 3dsmax that work just fine during serialization. Moreover, the problematic models go successfully through the rest of my scene setup, except that I can’t seem to get the said troublesome models to receive shadows (or maybe cast, I didn’t figure that one yet). I’ve looked through the .mtl files extensively to see if something was different, all I found was that some Ke (emissive) values were set to 1.0 1.0 1.0, but that shouldn’t matter since I’m modifying the material on import and nulling any emissive/ambient texture and setting the values to a custom defined color on import (plus I tried setting them to 0 0 0 manually in the .mtl and that didn’t change anything). I also tried setting COMPUTE_NORMALS = true
on the OBJFileLoader, but to no avail (and the .obj files in question define normals).
One thing I haven’t fully grasped yet is that the models causing the serialization error and not showing shadows trigger quite a few Setting vertex data kind 'position' with an empty array
errors on import. I’ve done a quick test and I’m getting the same result even if my process is as simple as opening 3DsMax, creating a box and a sphere, assigning a standard material to each and exporting to OBJ.
I’m trying to clean up the scene as much as I can during setup and am also recentering the models since they often have a misplaced origin that ends up far away (although not always). Here’s a snippet of the kind of setup I’m running in the Scene Loaded callback:
DoStuffToSetupSceneHere(babylonScene: Scene) {
this.engine.clearInternalTexturesCache();
this.scene = babylonScene;
this.scene.executeWhenReady( () => {
this.setupScene();
});
}
…where setupScene contains multiple functions such as:
configureSceneMeshes() {
this.scene.blockfreeActiveMeshesAndRenderingGroups = true;
// Clearing empty meshes
for ( let mesh of this.scene.meshes ) {
if ( typeof mesh.subMeshes === undefined
|| mesh.subMeshes === undefined
|| mesh.subMeshes === null
|| typeof mesh.subMeshes[Symbol.iterator]!=='function'
|| mesh.getTotalVertices() == 0
|| !(mesh instanceof Mesh) ) {
mesh.dispose();
}
}
this.scene.blockfreeActiveMeshesAndRenderingGroups = false; // Resetter à la bonne valeur
this.sceneExtent = this.scene.getWorldExtends();
this.sceneMiddle = Vector3.Center(this.sceneExtent.max, this.sceneExtent.min);
this.sceneSize = Vector3.Distance(this.sceneExtent.max, this.sceneExtent.min);
var rescaleFactor = 1;
if ( this.sceneSize > 2500 ) {
rescaleFactor = Math.round(2000*100 / this.sceneSize) / 100;
}
for ( let material of this.scene.materials ) {
if ( Object.keys(material.meshMap).length > 1 ) {
const chunkSize = 500;
var chunks = Object.values(material.meshMap).map((mesh, i) => {
return i % chunkSize === 0 ? Object.values(material.meshMap).slice( i, i + chunkSize ) : null;
}).filter((mesh) => { return mesh; });
for (let chunk of chunks) {
Mesh.MergeMeshes(chunk as Array<Mesh>, true, true);
}
}
this.setupMaterialAsPbr(material);
// this.setupMaterialAsStandard(material);
}
// Recentering remaining meshes
for ( let mesh of this.scene.meshes ) {
// console.log(mesh.id,'\noriginal position: ',mesh.position,'\noriginal abs pivot: ',mesh.getAbsolutePivotPoint(),'\noriginal pivot: ',mesh.getPivotPoint());
if ( mesh instanceof Mesh && mesh.getTotalVertices() > 0 ) {
if ( rescaleFactor !== 1 ) {
mesh.scaling = new Vector3(rescaleFactor, rescaleFactor, rescaleFactor);
}
mesh.translate(this.sceneMiddle, -1*rescaleFactor, Space.WORLD);
mesh.bakeCurrentTransformIntoVertices();
mesh.freezeWorldMatrix();
}
// console.log(mesh.id,'\nnew position: ',mesh.position,'\nnew abs pivot: ',mesh.getAbsolutePivotPoint(),'\nnew pivot: ',mesh.getPivotPoint());
mesh.isPickable = false;
mesh.doNotSyncBoundingInfo = true;
if (!mesh.material || (mesh.material instanceof StandardMaterial && !mesh.material.diffuseTexture) || (mesh.material instanceof PBRMaterial && !mesh.material.albedoTexture)) {
mesh.enableEdgesRendering();
mesh.edgesRenderer.edgesWidthScalerForOrthographic = 10000;
}
mesh.edgesWidth = this.defaultEdgesWidth;
mesh.edgesColor = new Color4(0, 0, 0, 1);
}
this.sceneExtent = this.scene.getWorldExtends();
this.sceneMiddle = Vector3.Center(this.sceneExtent.max, this.sceneExtent.min); // Devrait maintenant être équivalent à (0,0,0)
this.sceneSize = Vector3.Distance(this.sceneExtent.max, this.sceneExtent.min);
}
…and setting up the light/shadows:
setupLighting() {
// Lighting
this.sunTarget = new Vector3(this.sceneMiddle.x, this.sceneExtent.min.y, this.sceneMiddle.z);
this.sunDistance = Vector3.Distance(this.sunTarget, this.sceneExtent.max);
this.sunLight = new DirectionalLight("directionalLight", Vector3.Zero(), this.scene)
this.sunLight.diffuse = Color3.FromHexString(this.sunColor);
this.sunLight.specular = new Color3(1, 1, 1);
// Shadows
this.sunLight.shadowMinZ = this.sunDistance;
this.sunLight.shadowMaxZ = 3 * this.sceneSize + 100;
// this.sunLight.autoUpdateExtends = false;
this.sunLight.autoUpdateExtends = true;
// this.sunLight.autoCalcShadowZBounds = true;
this.sunLight.shadowOrthoScale = 0;
this.sunLight.shadowFrustumSize = 0;
this.sunShadows = new ShadowGenerator(1024, this.sunLight, true);
this.sunShadows.getShadowMap().refreshRate = RenderTargetTexture.REFRESHRATE_RENDER_ONCE;
this.sunShadows.bias = 0.0025;
this.sunShadows.normalBias = 0.35;
this.sunShadows.useContactHardeningShadow = true;
this.sunShadows.contactHardeningLightSizeUVRatio = .04;
this.sunShadows.setDarkness(0.15);
for (let mesh of this.scene.meshes) {
if (mesh.id !== 'skybox') {
this.sunShadows.addShadowCaster(mesh, true);
if (!mesh.material || (mesh.material instanceof StandardMaterial && !mesh.material.diffuseTexture) || (mesh.material instanceof PBRMaterial && !mesh.material.albedoTexture)) {
this.sceneMeshesMap.get(mesh.uniqueId).receiveShadows = true;
mesh.receiveShadows = true;
}
}
}
this.updateSun();
}
And here’s how we’re calling the Serialization:
sceneLoaded(sceneFile: File, babylonScene: Scene) {
DoStuffToSetupSceneHere(babylonScene) ;
this.scene.executeWhenReady(() => {
const serializedScene = SceneSerializer.Serialize(this.scene);
const strScene = JSON.stringify(serializedScene);
broadcast resulting file(strScene);
});
}
Any hint would be appreciated. I can provide some sample files too.