List all scene cameras?

Hi there,

I’m looking to switch from Babylonjs to Threejs.
I was used to access a lot of elements directly from the scene in Babylonjs.
I did this for example to list all the scene camera’s with scene.cameras

Is there a way in threejs to do the same? I know you can traverse the scene each time, but I would prefer to be able to use a direct category class to access all the camera’s, meshes, etc…

Thanks
Pieter

Cameras are not required to be elements of scenes – i.e. from JavaScript point of view, they are independent objects. However, you can add the cameras to the scene (or to other objects). In this case, the list of cameras can be extracted by:

var allCameras = scene.getObjectsByProperty( 'isCamera', true );

This traverses the scene. You might want to set allCameras once, and then reuse it.

In case you continuously add/remove cameras, a better approach is to keep your own list of cameras and avoid constant traversing of the whole scene.

3 Likes

Ok, that makes sense, thanks for your reply!
I already tried this with:

scene.getObjectsByProperty('type', 'PerspectiveCamera') as PerspectiveCamera[]

But this will only get me the perspective camera’s off coarse :slight_smile:
Let’s say I would like to toggle through the list of camera’s, what’s the best way to do this?

I’m used to do this using scene.activeCamera = ... but I can’t seem to find the proper alternative in three.

Thanks for the help!
Pieter

once you have your list of cameras you can just choose which camera to render the scene with eg…

renderer.render(scene, allCameras[idx])
idx++ // or any other way to increment the camera array idx

Yes, the way I was trying to do this was using

      const cam = (scene.getObjectsByProperty('type', 'PerspectiveCamera') as PerspectiveCamera[]).find(camera => camera.name === cam_track_name_active)
      if (!cam)
        return
      renderer.render(scene, cam)
      console.log('cam', cam.name, cam.position, cam.rotation, cam.zoom, cam.fov, cam.near, cam.far)

Log output:

cam WebGLScrollCam_01_Design Vector3 {x: 6.4161644, y: 1.59999955, z: -23.78284}x: 6.4161644y: 1.59999955z: -23.78284[[Prototype]]: Object Euler {isEuler: true, _x: 2.856280822244528, _y: 0.11301118720663712, _z: -3.108527237449751, _order: 'XYZ', …}isEuler: true_onChangeCallback: ƒ onRotationChange()_order: "XYZ"_x: 2.856280822244528_y: 0.11301118720663712_z: -3.108527237449751order: (...)x: (...)y: (...)z: (...)[[Prototype]]: Object 1 55.00000065335058 0.1 10000

So the camera is found, and should be activated. However I’m still getting only a default camera which was set earlier as a default camera when setting up the scene.

The camera with the name cam_track_name_active is being loaded along with one of my glb files that contains the animated camera.

For some reason it’s in the scene but switching to it doesn’t seem to work.
Any other things I can try?

Thanks
Pieter

Also I tried this in the console of my chrome browser.
I’ve made scene & renderer available there:

scene.getObjectsByProperty('isCamera', true)[1].name
> 'WebGLScrollCam_01_Design'
renderer.render(scene, scene.getObjectsByProperty('isCamera', true)[1])
> undefined
renderer
> WebGLRenderer {isWebGLRenderer: true, domElement: canvas, debug: {…}, autoClear: true, autoClearColor: true, …}

why is returning renderer.render(scene, scene.getObjectsByProperty('isCamera', true)[1]) undefined? is that the normal return?

Thanks

Ok, so I managed to resolve the issue.
Here is how for anyone that would run into the same issue.

To give the full context, I’m working in Vue3 & Vite.

  function animate() {
    if (!container || !store_canvas._camera.activeCamera)
      return
    controls.update()
    renderer.render(scene, store_canvas._camera.activeCamera)
    requestAnimationFrame(animate)
  }

  window.addEventListener('resize', onWindowResize)
  animate()

My models are loaded via a function to keep my code compact & structured. This makes it a bit harder to update the camera value in the renderer.render(scene, camera) as this local original camera will overwrite the loaded camera. The one which came in through the loaded *.glb file.

In Vue I’m using pinia for state management, so now i store the active camera via a state, so it can be updated externally from the main threejs render function.

      const cam = (scene.getObjectsByProperty('type', 'PerspectiveCamera') as PerspectiveCamera[]).find(camera => camera.name === cam_track_name_active)
      if (!cam)
        return
      store_canvas._camera.activeCamera = cam

Hope this makes sense… now onto converting my animations from babylonjs to threejs :slight_smile:
Pieter