Skip to main content

Camera Control and animation

The viewer provides a level of abstraction over the cameras in the scene to make it easy to manage multiple cameras, enable/disable/configure camera controls(like OrbitControls), and integrate with post-processing and XR pipelines. This is managed in a class called CameraController. On initialisation, the viewer creates a default PerspectiveCamera with a CameraController with OrbitControls which is used for scene rendering. The active camera controller can be accessed by:

const controller = viewer.scene.activeCamera;
// get the threejs camera
const perspectiveCamera = controller.cameraObj;
// get orbit controls
const orbitControls = controller.controls;

activeCamera is the camera that is used for scene rendering. This can be set to a custom camera like:

const cameraObj = new PerspectiveCamera();
...
viewer.scene.activeCamera = viewer.createCamera(cameraObj);

createCamera above, creates and returns a CameraController instance. It is automatically ensured that only one controller is created for a camera instance, even if this function is called multiple times. To get the CameraController from the camera use controller = cameraObj.userData.iCamera

tip

three.js internals can be imported directly from webgi

import { PerspectiveCamera, Vector3, Vector2, Texture} from "webgi";

The active camera instance and view can also be managed from events in the scene objects. To activate a scene camera, get the instance from the camera and dispatch the activateMain event.

camera.dispatchEvent({type: 'activateMain', camera: camera})

Here, camera is an instance of PerspectiveCamera or OrthographicCamera. The camera in the event can be set to null to activate the default camera in the scene. To change the view of the camera, dispatch the setView event.

camera.dispatchEvent({type: 'setView', camera: camera})

This copies the properties from the camera and sets them on the active camera.

Camera Transform

The camera position and target can be set directly in the controller;

viewer.scene.activeCamera.position = new Vector3(2, 3, -5);
viewer.scene.activeCamera.target = new Vector3(0, 2, 0);

// or
viewer.scene.activeCamera.position.set(2, 3, -5);
viewer.scene.activeCamera.positionUpdated(); // this must be called to notify the controller on value update
viewer.scene.activeCamera.target.set(0, 2, 0);
viewer.scene.activeCamera.targetUpdated(); // this must be called to notify the controller on value update
note

Camera global scale must be set to 1.0 in x, y and z. This is automatically ensured while models and cameras are imported, but it must be taken care of when updating models and hierarchy by code.

Camera Options

Various camera options can be get/set from the controller:

const options = viewer.scene.activeCamera.getCameraOptions();
options.fov = 25;
viewer.scene.activeCamera.setCameraOptions(options);

The following options can be set:

  • fov: Vertical Field of View in degrees. Perspective Camera only.
  • zoom: Camera zoom value
  • aspect: Camera aspect ratio. Default is set to 'auto', which calculates the aspect ratio based on canvas size, and updates on size change.
  • controlsEnabled: Enable or disable Orbit Controls etc.
  • frustumSize: for Orthographic camera.

Controls Options

Options for controls like OrbitControls can be set directly after accessing it. For example:

const controls = viewer.scene.activeCamera.controls;
controls.autoRotate = true;
controls.autoRotateSpeed = true;
controls.enableDamping = true;
controls.rotateSpeed = 2.0;
controls.enableZoom = false;
...

For all properties, see three.js docs on OrbitControls

tip

OrbitControls in webgi also support smooth dolly zooming with mouse wheel when used with enabledDamping=true. To control the speed and max speed of this zooming see controls.maxSpeed and controls.zoomSpeed.

note

The OrbitControls in webgi is extended for some extra performance improvements, and camera movements are syned with the render loop. So, prefer to use the instance of OrbitControls in the default camera instead of passing in a custom one.

info

Currently only OrbitControls is supported, internally, but others can be added by extending CameraController.

Here's a codepen with live demo for accessing and modifying the camera properties:

Camera Animation and Views

CameraViewPlugin can be used to manage and animate between multiple camera states(views).

First add the plugin (This is done in addBasePlugins):

await viewer.addPlugin(CameraViewPlugin)

Then get the reference to the plugin

const camViewPlugin = viewer.getPlugin(CameraViewPlugin)

Camera views can be created in the editor and downloaded as a preset and applied at runtime or they can be added programmatically like below:

  let view = camViewPlugin.getCurrentCameraView(viewer.scene.activeCamera) // Get the current camera state
view.position.set(-2,4,5)
view.target.set(0,1,0)
camViewPlugin.camViews.push(view) // save it for later.
// add more views

Now we can animate the camera to a view:

  await camViewPlugin.animateToView(camViewPlugin.camViews[1], 2000) // 2000 ms is the duration

Once the camera views are added, they can be looped or played through once.

camViewPlugin.animDuration = 3000 // ms, default duration of one animation
await camViewPlugin.animateAllViews() // This will loop once
camViewPlugin.viewLooping = true // This will loop indefinitely

Interpolation of camera position is spherical by default to ensure smooth movement, but it can be changed to linear for direct interpolation. Animation easing is set to easeInOutSine by default, but can be set to any easing from PopmotionPlugin.

Check the API docs for more parameters in CameraViewPlugin

Here is a codepen with live demo for the CameraViewPlugin API: