How do I save a scene?

Good afternoon :slightly_smiling_face:

I created a scene: built the walls, added furniture, textures and lights. OK)

Now I need to save this scene so that later I can load it back.
I found toJSON () in Scene. Ok, no problem here.
Problems start when you need to create JSON:

let json = scene.toJSON ();
let save = JSON.stringify (json);

JSON.stringify () - the function slows down very much, the computer freezes. An error appears: Invalid string length

How do I save a scene? :pensive:

That seems to indicate that your scene is very complex. However, there is no way around using Scene.toJSON() and then JSON.stringify() if you want to use the three.js JSON format. The loading or deserialization process would look like so:

const scene = new THREE.ObjectLoader().parse( JSON.parse( string ) );

Do you mind demonstrating this issue?

1 Like

I want to create a whole interior with many different models. The sofa here weighs 30 MB and is high-poly.
As a result, if there are many models in the scene, then the JSON length from the scene becomes large.
As I understood, JSON.stringify () has a length limit.

I decided to do it like this: I created an array objects = [] and in it I save all the objects added to the scene.
Using for (let o in objects), I translate the objects into json JSON.stringify (objects [o]) one by one and save them in the database. This way the computer does not freeze.
When loaded with ajax, one at a time, get and add to the scene scene.add (object) :roll_eyes:

Thanks for const scene = new THREE.ObjectLoader (). Parse (JSON.parse (string)). Translated json into normal form. :slightly_smiling_face:

I create a scene and save it

All scene objects from the objects = [] array were saved in the database

Loading the project. Add objects to the scene

 for(let ids in project.objects_ids) {
                $.ajax({
                    url: '/three-project-load-objects',
                    method: 'POST',
                    data: { 'save_id': project.id, 'object_id': project.objects_ids[ids] },
                    async: false,
                    headers: {
                        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
                    },
                    success: function (db) {
                        if (db.status == 'ok') {
                            
                            let object = new THREE.ObjectLoader().parse( JSON.parse( db.object[0].object ) );
                            console.log(object);
                            
                            scene.add(object);
                        }
                    },
                });
            }

Something objects in the scene did not stand up correctly! :roll_eyes:

Before calling toJSON(), you should ensure to call updateMatrixWorld() on the respective object.

3 Likes

Instead of saving your complete scene as JSON, you could generate a JSON that stores model paths associated with position/rotation/scale of each model, as well as positions of walls/corners and texture paths.
When loading, you would have to load each path and apply the transforms back to it.
You would save quite a lot of data, because your not storing geometry.
You just store information that lets you rebuild the scene

4 Likes

Can you please more about this? About the matrix. I read the documentation but didn’t quite understand how to work with the matrix. :roll_eyes:

I managed to load the scene correctly.
I save the scene


Loading the scene. Floor, walls and light sources are in place. Everything is correct, but the helpers of the light are broken.


Object when I save.


Object after loading

It looks like the helper is not saved correctly when translated into json :roll_eyes:

I think I understood. ObjectLoader does not understand the type - helper

Yep, helpers are not yet supported.

I save my scenes. But I don’t do it the prescribed way because it creates such HUGE files. Instead I save metadata that can be used to reconstruct a scene. These are very small in comparison.

Hello

As @Fluqz said, why not saving only complex objects’ position/rotation/… and the url to the model to load in your scene?

You can do this by creating a class that extends Object3D and have a modelURL (by exemple) property and you then have to override the toJSON method to serialize every properties but not children…
Then to load it again, your class will be created by the json loader adinng simply this modelURL that your class know how to load :wink:

3 Likes

That’s it!
Thank you.
I was trying to fix this issue for hours and that was the solution. Couldn’t find it anywhere else.
I created this account only to like and reply to your post :joy:
Thank you.

Hello guys!
I am trying to achieve this with React Three Fiber in Next.js 14 but I am a bit lost.
My idea was to create some kind of global state with zustand, here is a simple data structure:

And then when the user clicks the add button I simply add a new element to my scene data structure like this:

So by adding the new element to the scene the component containing all the scene logic will rerender and create a new mesh component:

I tried like this and It could work but I think It’s not the correct way… Do you think I am going to the right direction? Can I have some feedback on how to save and import my scene efficiently and store the scene on a DB?

Thanks!
Chris