I’m trying to implement a saving and loading feature on a scene made with imported GLB models, a dynamic skybox and post-processing effects (also contains a GizmoManager) by following this guide, but I’m getting an error when loading the saved scene. What I want is to save the scene completely to a .babylon file. On loading a scene from a .babylon file, I want the new scene to completely replace the current scene.
PLAYGROUND LINK (Press 3 to save and 4 to load)
When I try to load the saved scene, I’m getting this error:
The loading part work for simple scenes like basicScene.zip (52.0 KB) (but not in the playground), so I’m guessing the problem is in the saving part?
I got the same error when I exported the scene with the inspector, but it seems to work fine when exported as a GLB file instead of .babylon file. I can use the GLTF exporter, but it seems like some things are not supported yet.
Relevant code:
/**
* Serializes the scene and saves it to a file.
*/
saveScene() {
if (!this.scene) {
throw new Error("No scene");
}
if (this.savedSceneURL) {
window.URL.revokeObjectURL(this.savedSceneURL);
}
const serializedScene = BABYLON.SceneSerializer.Serialize(this.scene);
const strMesh = JSON.stringify(serializedScene);
if (
this.savedSceneFilename.toLowerCase().lastIndexOf(".babylon") !==
this.savedSceneFilename.length - 8 ||
this.savedSceneFilename.length < 9
) {
this.savedSceneFilename += ".babylon";
}
const blob = new Blob([strMesh], { type: "octet/stream" });
// turn blob into an object URL; saved as a member, so can be cleaned out later
this.savedSceneURL = (window.webkitURL || window.URL).createObjectURL(blob);
const link = window.document.createElement("a");
link.href = this.savedSceneURL;
link.download = this.savedSceneFilename;
const clickEvent = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: false,
});
link.dispatchEvent(clickEvent);
}
/**
* Loads a scene from a file.
*/
loadScene() {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = ".babylon";
fileInput.onchange = (event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
const fileURL = URL.createObjectURL(file);
console.log(fileURL);
BABYLON.SceneLoader.LoadAsync("", fileURL, this.engine, null, ".babylon").then(
(scene: BABYLON.Scene) => {
if (scene) {
this.scene?.dispose();
this.scene = scene;
this.scene.activeCamera = this._createController();
}
}
);
}
};
fileInput.click();
}