1. A concise explanation of the problem you're experiencing.
I have an entity I would like to update in realtime from a websocket. In order to simulate this I created an entity and update its position in the onTick event handler. I want a camera to track this entity and I use the position and rotation of the entity to make calls to lookAtTransform. When I do this it seems the camera and entity updates are out of sync somehow even though they are both computed in the same handler. If I pause the handler (just return from the function). I see the camera match up with the entity how I would expect. I want to know why this is and the exact update order that occurs during scene rendering. Currently it seems that camera updates happen first then the entity updates and then rendering occurs. I suspect this because if I put my entity update logic inside of postUpdate and my camera logic in preUpdate, the two stay in sync as I would expect. The sandcastle demo below shows the working method with the original method commented out at the bottom.
2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.
var viewer = new Cesium.Viewer('cesiumContainer', {
infoBox: false, //Disable InfoBox widget
selectionIndicator: false, //Disable selection indicator
shouldAnimate: true, // Enable animations
terrainProvider: Cesium.createWorldTerrain()
});
//Enable lighting based on sun/moon positions
viewer.scene.globe.enableLighting = true;
//Enable depth testing so things behind the terrain disappear.
viewer.scene.globe.depthTestAgainstTerrain = true;
//Set the random number seed for consistent results.
Cesium.Math.setRandomNumberSeed(3);
//set labels for sun
var sunPositionProperty = new Cesium.CallbackProperty(function(time, result){
Cesium.Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame(time, result);
return Cesium.PositionProperty.convertToReferenceFrame(
time,
result,
Cesium.ReferenceFrame.INERTIAL,
Cesium.ReferenceFrame.FIXED,
result);
}, false);
var sunEntity = viewer.entities.add({
position : sunPositionProperty,
label : {
text : 'Sun'
}
});
var lineP1 = Cesium.Cartesian3.fromDegrees(-75, 35);
var lineP2 = Cesium.Cartesian3.fromDegrees(-175, 35);
var line_positions = [lineP1, lineP2];
function line_callback(time, result){
var sun_pos = {};
var curr_pos = {};
entity.position.getValue(time, lineP1);
sunPositionProperty.getValue(time, sun_pos);
Cesium.Cartesian3.subtract(sun_pos, lineP1, curr_pos);
Cesium.Cartesian3.normalize(curr_pos, curr_pos);
Cesium.Cartesian3.multiplyByScalar(curr_pos, 30, curr_pos);
Cesium.Cartesian3.add(curr_pos, lineP1, lineP2);
return line_positions;
}
var lineEntity = viewer.entities.add({
polyline : {
positions : new Cesium.CallbackProperty(line_callback, false),
width : 5,
material : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.YELLOW),
}
});
//Compute the entity position property.
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 10000000);
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : '../../../../Apps/SampleData/models/CesiumAir/Cesium_Air.glb',
position : position,
orientation : orientation,
model : {
uri : '../../../../Apps/SampleData/models/CesiumAir/Cesium_Air.glb',
minimumPixelSize : 128,
maximumScale : 20000
}
});
var VIEW_TYPE = 0;
//viewer.trackedEntity = entity;
//viewer.scene.screenSpaceCameraController.enableInputs = false;
viewer.scene.sun.glowFactor = 25;
// disable the default event handlers
viewer.scene.screenSpaceCameraController.enableRotate = false;
viewer.scene.screenSpaceCameraController.enableTranslate = false;
viewer.scene.screenSpaceCameraController.enableZoom = false;
viewer.scene.screenSpaceCameraController.enableTilt = false;
viewer.scene.screenSpaceCameraController.enableLook = false;
var startMousePosition;
var mousePosition;
var flags = {
looking : false,
zooming: false
};
var canvas = viewer.canvas;
var handler = new Cesium.ScreenSpaceEventHandler(canvas);
var cameraRot = new Cesium.Cartesian2(0,0);
var cameraZoom = -100;
handler.setInputAction(function(movement) {
flags.looking = true;
mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
handler.setInputAction(function(movement) {
mousePosition = movement.endPosition;
var width = canvas.clientWidth;
var height = canvas.clientHeight;
// Coordinate (0.0, 0.0) will be where the mouse was clicked.
if(flags.looking == true) {
var x = (mousePosition.x - movement.startPosition.x) / width;
var y = (mousePosition.y - movement.startPosition.y) / height;
var lookFactor = Math.abs(cameraZoom)*0.15;
cameraRot.x += x* lookFactor;
cameraRot.y += y* lookFactor;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(function(position) {
flags.looking = false;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
handler.setInputAction(function(movement) {
cameraZoom += movement;
if(cameraZoom > 0 && cameraZoom + movement == 0)
cameraZoom = -1;
if(cameraZoom < 0 && cameraZoom + movement == 0)
cameraZoom = 1;
}, Cesium.ScreenSpaceEventType.WHEEL);
var paused = false;
Sandcastle.addToolbarButton('Pause', function() {
paused = !paused;
});
viewer.scene.postUpdate.addEventListener(function(scene)
{
if(paused)
return;
var entPos = new Cesium.Cartesian3(0,0,0);
entity.position.getValue(viewer.clock.currentTime, entPos);
Cesium.Cartesian3.add(entPos, new Cesium.Cartesian3(1050,0,0), entPos);
entity.position.setValue(entPos);
//console.log("entity pos: "+entPos);
let modelMat = new Cesium.Matrix4();
let dir = new Cesium.Cartesian3(0,0,cameraZoom);
entity.computeModelMatrix(viewer.clock.currentTime, modelMat);
});
viewer.scene.preUpdate.addEventListener(function(scene)
{
let modelMat = new Cesium.Matrix4();
let dir = new Cesium.Cartesian3(0,0,cameraZoom);
entity.computeModelMatrix(viewer.clock.currentTime, modelMat);
var calcPos = new Cesium.Cartesian3(0,0,0);
Cesium.Matrix4.getTranslation(modelMat, calcPos);
//console.log("camera pos: "+calcPos);
viewer.camera.lookAtTransform(modelMat, dir);
viewer.camera.rotateLeft(cameraRot.x );
viewer.camera.rotateDown(cameraRot.y);
});
/* This doesn't work...why??
viewer.clock.onTick.addEventListener(function(clock) {
if(paused)
return;
var entPos = new Cesium.Cartesian3(0,0,0);
entity.position.getValue(viewer.clock.currentTime, entPos);
Cesium.Cartesian3.add(entPos, new Cesium.Cartesian3(1050,0,0), entPos);
entity.position.setValue(entPos);
//console.log("entity pos: "+entPos);
let modelMat = new Cesium.Matrix4();
let dir = new Cesium.Cartesian3(0,0,cameraZoom);
entity.computeModelMatrix(viewer.clock.currentTime, modelMat);
var calcPos = new Cesium.Cartesian3(0,0,0);
Cesium.Matrix4.getTranslation(modelMat, calcPos);
//console.log("camera pos: "+calcPos);
viewer.camera.lookAtTransform(modelMat, dir);
viewer.camera.rotateLeft(cameraRot.x );
viewer.camera.rotateDown(cameraRot.y);
});
*/
3. Context. Why do you need to do this? We might know a better way to accomplish your goal.
I need this to work both for czml and realtime updates for an application that must be able to handle streamed realtime data and also historical playback for after-action review.
4. The Cesium version you're using, your operating system and browser. Latest, MacOSX, Chrome