automating camera: lookAt vs flyToBoundingSphere


I need to automate the camera until the user takes control (tries to manipulate it herself).

I’d like to operate the camera using target and HeadingPitchRange offset.

  • flyToBoundingSphere positions the camera imprecisely, so I got weird animation (run below code)

  • lookAt changes reference frame so that when the user tries to tilt the camera with middle mouse button camera stays unchanged and I fail to detect user interaction (un-comment line 27)

Please advise.

Thank you.

var C = Cesium

var viewer = new C.Viewer(‘cesiumContainer’);

var camera =

var a = { lon: -117.25, lat: 32.71 }

var b = { lon: -117.00, lat: 32.71 }

var duration = 3000

function position(time) {

var t = C.JulianDate.toDate(time).valueOf() / 1e3 % duration

return C.Cartesian3.fromDegrees(

C.LinearApproximation.interpolateOrderZero(t, [0, duration], [a.lon, b.lon], 1)

, C.LinearApproximation.interpolateOrderZero(t, [0, duration], [,], 1)



var automate = true

var offset = new C.HeadingPitchRange(0, -Math.PI/2*0.99, 100)

var positionSet

var positionGot = camera.position

viewer.clock.onTick.addEventListener(function() {

if (!automate) return

if (camera.position.equals(positionGot)) { // no change => continue automating

positionSet = position(viewer.clock.currentTime)

// imprecise positioning leads to bad animation

camera.flyToBoundingSphere(new C.BoundingSphere(positionSet, 1), { duration: 0, offset: offset })

// locks tilting

// camera.lookAt(positionSet, offset)

positionGot =

} else { // user intruded => stop automating

automate = false

// to “release” the camera - restore reference frame set by camera.lookAt

camera.flyToBoundingSphere(new C.BoundingSphere(positionSet, 1), { duration: 0, offset: offset })



I noticed you don’t like using semi-colons, but I’m not sure that’s causing any problems in this case.

If you put this line right after the lookAt function call


You can then tilt and stop the automation. This sets the transform back to Earth’s. But put that line before you clone the position.

It works!

Previously I’ve tried

  • camera.transform = C.Matrix4.IDENTITY // exception

  • camera.transform = C.Matrix4.IDENTITY.clone() // moves the camera to the north pole

I’m a bit surprised _setTransform does something different.

OK, so I’ll use camera.lookAtTransform(C.Matrix4.IDENTITY) which does the same, but is public.

Thank you!


While my problem at hand is resolved, I wonder if the following are bugs or features:

  • imprecise camera positioning by flyToBoundingSphere

  • camera lock on the target after lookAt

  • camera lock on the position where the tracked entity was when the tracking was stopped

Actually there is no .transform, but there is a ._transform. However just setting ._transform doesn’t seem to work either.

._setTransform does more than just change ._transform. It changes a bunch of other properties according to this new change, one of which is the camera position to the new transform. lookAtTransform itself calls ._setTransform. .lookAt calls lookAtTransform if it has only 2 parameters. and sets the transform to the ENU of the target. However .lookAtTransform doesn’t change the transform back since in some cases people might want to keep it that way.

As an alternative to calling .setTransform after .lookAt perhaps you could clone camera position and only transform that to world coordinates and save to positionGot.

Don’t do the ._setTransform and test these console logs:

viewer.clock.onTick.addEventListener(function() {



Before you interrupt the automation reg is constant while wc continuously shifts, which is correct for their respective transforms. After interrupting they are the same. Then add the camera._setTransform(C.Matrix4.IDENTITY); and try the test again. Reg and WC are the same, which all makes sense.

Aha, looking at function tilt3D in ScreenSpaceCameraController.js there is this:

if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {return;}

That explains why it only works when you set to IDENTITY matrix.