Three.js Editor: How to export a scene or project including the camera's projection matrix?

Hello everyone!

I would like to do the following with the three.js editor (code here):

  1. Build a scene
  2. Export that scene/project to keep a copy saved for later use
  3. Import a scene/project from disk when needed (to continue my work)

As a minimal example (you can test it using the online editor):

  • For nr. 1: Start from a blank scene and add an Ambient Light and move the camera’s position and change it’s orientation.

  • Then for nr. 2: Go to the Menu Bar, select “File”, then “Export Scene”.

    (As an additional step move the camera again, to verify if importing the previous scene loads the previous camera position and orientation.)

  • Finally for nr. 3: Go to the Menu Bar, select “File”, then “Import” and pick the previously saved scene.

Unfortunately the scene/project is not the same scene/project that was exported. There are two issues I see:

  1. The scene that is currently open does not disappear/ is not cleared. Therefore importing a scene from a JSON file adds the objects (in this case a new ambient light, as defined in the saved file from the above example) to the current scene. You can see you will have 2 ambient lights in the scene.

  2. The camera information is not saved to the JSON file. The camera position and orientation is not reestablished to how it was when the scene was saved.

At the moment I am more concerned about nr.2, because I can avoid problem nr. 1 by using the FileLoader class to load the exported JSON file when launching the Editor.

Does anyone know how to export the camera’s matrix to a JSON file using the Three JS editor?

I am aware the PerspectiveCamera class has a .toJSON method, I just don’t know how to call it from the running three.js Editor.

This is how the scene.json file that I currently get looks like when I export the above mentioned scene:

{
	"metadata": {
		"version": 4.6,
		"type": "Object",
		"generator": "Object3D.toJSON"
	},
	"object": {
		"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
		"type": "Scene",
		"name": "Scene",
		"layers": 1,
		"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
		"up": [0,1,0],
		"children": [
			{
				"uuid": "770803a8-96cf-4c7b-b3cb-682a80d77591",
				"type": "AmbientLight",
				"name": "AmbientLight",
				"layers": 1,
				"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1],
				"up": [0,1,0],
				"color": 2236962,
				"intensity": 1
			}]
	}
}

And this is what expect to get (this includes the camera and ambient light and opens fine using the FileLoader class):

{
	"metadata": {
		"type": "App"
	},
	"project": {
		"shadows": true,
		"vr": false
	},
	"camera": {
		"metadata": {
			"version": 4.5,
			"type": "Object",
			"generator": "Object3D.toJSON"
		},
		"object": {
			"uuid": "60EBAF60-53DA-47B0-A028-8FC031B708F6",
			"type": "PerspectiveCamera",
			"name": "Camera",
			"layers": 1,
			"matrix": [0.970041,0,-0.242943,0,-0.048226,0.980099,-0.785398,0,0.238108,0.198509,0.950736,0,10,0,10,1],
			"fov": 50,
			"zoom": 1,
			"near": 0.1,
			"far": 100000,
			"focus": 10,
			"aspect": 1.428977,
			"filmGauge": 35,
			"filmOffset": 0
		}
	},
	"scene": {
		"metadata": {
			"version": 4.5,
			"type": "Object",
			"generator": "Object3D.toJSON"
		},
			"object": {
                "uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
                "type": "Scene",
                "name": "Scene",
                "layers": 1,
                "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
                "up": [0,1,0],
                "children": [
                    {
                        "uuid": "e36c689a-ba6e-4dae-a126-b864132885c0",
                        "type": "AmbientLight",
                        "name": "AmbientLight",
                        "layers": 1,
                        "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,2,0,1],
                        "up": [0,1,0],
                        "color": 16777215,
                        "intensity": 2
                    }]
            }
	}
}

So, how do I go about saving the camera position (in particular the camera matrix) when using the Three.js Editor? Is there a direct or indirect way of obtaining the Three.js Editor’s camera matrix for later use?

I appreciate your help with this.

I think its not exporting the camera because the camera is not a child of “Scene” by default.

If you click the Scene node then Add a new Perspective camera, you’ll get a new camera inside the scene, and exporting/loading that scene should contain the child camera.

That all said… the THREEJS editor serves more of an example of how you can implement/build your own 3d editing tools, rather than a fully fledged content generation tool by itself.

It just happens to be capable enough to create working standalone threejs apps. . so I’m not exactly sure how to solve this problem.

Additionally the threejs json format, while handy, is a bit brittle and changes from time to time, so your exported scenes may stop working with later revs of three.

If you want something more stable I suggest using GLTF (for human readable) or binary gltff (.glb) for size/performance. HOWEVER: I don’t think that format supports exporting the camera either… so… as I said… not exactly sure how to solve your problem.

Can you describe what you’re trying to build on a higher level and we can probably point you at some different approaches?

2 Likes

Hello @manthrax,

this did the trick!

By adding a new camera, adjusting it to the desired position/rotation, and exporting it, I was able to obtain that camera’s matrix from the exported JSON file. Then, I manually copied that matrix to my JSON file, which contains only the main camera (the one that is not a child of the scene) and the ambient light.

Using the FileLoader class, I can load this JSON file when launching the (self hosted) Three.js Editor and have a custom scene shown at startup with a custom camera location, which is what I was trying to achieve. Thank you very much for your help!


My immediate goal is to learn about the Three.js Editor, how it is build, what it is capable of, its limitations and also the scope of this tool.

Once I understand it better I might fork it and use it as a starter code for a self hosted customized version of the Three.js Editor that can be used for something similar to a room designer. A user can select furniture out of large set of 3d models place them in an empty room, move, rotate or remove the furniture as required. Then take a screenshot of the scene or save the project to disk (to continue work at a later time). I think the editor might have 95% of what is needed for a first minimal demo version of such a tool, but at present, I am still in the experimentation and understanding phase.

1 Like

Ahh awesome. Ok it sounds like you know what you’re doing.

Also a useful for inspiration (but slightly old open sourced project) is Blueprint3d. I’ve used it as the basis for other configurator type projects in the past.
Maybe it can give you some inspiration:

1 Like

Hi @manthrax,

that is amazing, might be a better basis for my project, thanks for sharing!

1 Like

Yeah It’s a good no-nonsense implementation, even tho it was written a while ago. For instance… they throttle the rendering to like 15 fps for performance on mobile devices, but nowadays mobile devices are way more capable, so you can remove that throttle and it runs much smoother.

The other tricky problems it does a decent job with solving:

Identifying the rooms formed by the user dragging out walls… and then creating shapes for the floors the rooms create. It uses a cycle detection routine to identify the room islands. The issue with textures going black when the windows / doors get dragged, was also easy to fix if I recall.

It does wall geometry creation with thickness and handles the corner mitering etc. It does door / window cutouts from the walls as well. iirc it uses the threejs shape/path extrusion for that.

It does some detection for placing/moving objects.

Each of those problems can be really tricky to solve.

1 Like

Yes, I can see that it already implements tons of features. It certainly solves more problems than I can at this point even imagine one would encounter. Studying and experimenting with the project’s codebase seems well worth it. It’s such a blessing. I will definitely fork it and start tinkering with it. Thanks again for sharing!

1 Like