Switching Multiple Cameras in a glTF Scene
This article explains how to define multiple cameras within the glTF 2.0 file format and switch between them dynamically in WebGL engines. While glTF natively stores multiple camera definitions and binds them to the scene hierarchy, the actual switching mechanism is handled during runtime by 3D rendering engines such as Three.js or Babylon.js.
Defining Cameras in the glTF Schema
The glTF specification defines cameras inside a top-level
"cameras" array. Each entry designates a camera type—either
"perspective" or "orthographic"—along with its
corresponding projection parameters (such as yfov,
znear, and zfar).
"cameras": [
{
"type": "perspective",
"perspective": {
"aspectRatio": 1.777,
"yfov": 0.785,
"zfar": 1000.0,
"znear": 0.1
},
"name": "OverviewCamera"
},
{
"type": "perspective",
"perspective": {
"aspectRatio": 1.777,
"yfov": 0.523,
"zfar": 500.0,
"znear": 0.1
},
"name": "CloseUpCamera"
}
]Assigning Cameras to Nodes
Cameras do not hold positional or rotational data directly. Instead,
they are assigned to nodes in the "nodes" array using their
zero-based index from the "cameras" array. The node
provides the spatial transformation (translation,
rotation, or matrix).
"nodes": [
{
"name": "OverviewNode",
"camera": 0,
"translation": [0.0, 5.0, 10.0]
},
{
"name": "CloseUpNode",
"camera": 1,
"translation": [0.0, 1.5, 2.0]
}
]When authoring in software like Blender, any camera added to the scene collection will automatically export as a camera assigned to a node, preserving its transform and field of view.
Accessing and Toggling Cameras at Runtime
Because glTF is a transmission format rather than an executable application, toggling cameras requires reading the parsed camera array in your rendering engine and updating the active camera passed to the render loop.
In Three.js
When using GLTFLoader, all cameras defined in the file
are extracted into an array located at gltf.cameras.
- Load and Store: Capture the array of cameras upon loading.
- Update Projections: Ensure that aspect ratios match the render window if resizing occurs.
- Switch Active Reference: Point your render loop to the desired camera instance.
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
let sceneCameras = [];
let activeCamera;
const loader = new GLTFLoader();
loader.load('scene.gltf', (gltf) => {
scene.add(gltf.scene);
// Store all cameras found in the glTF
sceneCameras = gltf.cameras;
// Set default camera (fallback to engine default if none exist)
activeCamera = sceneCameras[0] || defaultCamera;
});
// Function to toggle between cameras
function switchCamera(index) {
if (sceneCameras[index]) {
activeCamera = sceneCameras[index];
activeCamera.aspect = window.innerWidth / window.innerHeight;
activeCamera.updateProjectionMatrix();
}
}
// Render loop uses the active camera
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, activeCamera);
}In Babylon.js
Babylon.js imports glTF cameras and appends them to the scene's
camera list, accessible through scene.cameras.
BABYLON.SceneLoader.Append("", "scene.gltf", scene, function (scene) {
// Set active camera by name or index
scene.activeCamera = scene.getCameraByName("CloseUpCamera");
scene.activeCamera.attachControl(canvas, true);
});
function toggleCamera(cameraName) {
const targetCam = scene.getCameraByName(cameraName);
if (targetCam) {
scene.activeCamera.detachControl();
scene.activeCamera = targetCam;
scene.activeCamera.attachControl(canvas, true);
}
}By decoupling the camera properties in the "cameras"
array, applying transforms through "nodes", and handling
active view assignment via runtime loaders, glTF files can store complex
multi-camera setups that are switchable on demand.