How to fix flicker upon updating position of an entity?

Hello, so I have this issue where the model will ‘flicker’ whenever I update the position. Here is a sandcastle that reproduces the bug

If you just have a static (yellow) polyline and the model moving about it, there is no flicker. If you attach a polyline to the model and move that with it as well, there is a flicker. Notice that the polyline does not flicker, only the model, and that’s despite the model being what is being tracked, not the polyline.

Upon using my iPhone slow motion camera to see what is happening, it appears that the model is jumping forward to its next point and leaving the camera behind, and the next frame or so the camera will jump back to the model where it’s supposed to be.

I am simulating my use case by using a setInterval to update the point’s position, but in reality the ‘position’ is something I receive in real time. So I cannot know the future to use animations.

I am a good developer who searches google before asking questions, however the solution that I see is to use a callback property, thought that is not feasible for me either. Here is a sandcastle that uses a callback property to update the position of the perpendicular line, and that does fix it, but you can see the performance issues that are caused by the CallbackProperty when you crank up the number of points in the perpendicular line. That’s because CallbackProperty gets called every single frame, and Cesium cant handle redrawing the polyline every single frame even for a relatively modest number of points like 1000.

So does anyone know of a clever way to get around the flicker without using a callback property / animations?

Thank you

Not a complete solution yet, but two observations:

  • It seems to jump to a wrong position. It’s hard to capture, but visible here:
    Cesium Flicker Position
    (in reality, the flickering is much quicker - this is just captured with low FPS)
  • When omitting the viewer.trackedEntity = modelEntity; (and manually zooming to the model instead), it looks like it does not flicker any more. So the flickering in this case might be caused by a bug in the tracking mechanism (a wild guess for now…)

I wondered whether the flickering could be avoided by using a CallbackProperty only for the position of the model, but a quick test did not solve this (it might be worth another try, though). Maybe someone from the CesiumJS core squad has further ideas.

(That connection to the trackedEntity may warrant some further investigation regardless…)

1 Like

Thank you for the response Marco I appreciate you taking the time to look into this for me.

I did some more googling and saw that other people have what appears to be the same tracking-flicker bug except they get it when loading data from a czml, here is an issue from 2016 Weird interaction between CzmlDataSource.process and tracked entity · Issue #4647 · CesiumGS/cesium · GitHub Though they never found a solution.

I also tried using callback on the model position and it does not seem to work either.

After more research I believe I understand the issue more. When updating the position of a polyline, cesium seems to remove and then add the polyline back with the new positions, and the creation of this polyline is blocking the camera position update, so it only gets updated after the polyline is finished drawing. This would explain why the polyline doesn’t flicker only the model.

Once I understood this I was able to find a workaround, but it is very hacky. Here is the cesium sandcastle but I will also highlight what I did here for convenience. Basically I create the perpendicular line at the new point in advance, wait about 60ms and then jump the model to the next point, and then I wait another 10ms to remove the old line. This works in my browser if it doesn’t work in yours then you may need to increase the delays (which is why this workaround is still less than ideal).

let currentIndex = 0;
let entityIdCounter = 0; // Counter to be appended to entity ID

function updatePoint() {
    currentIndex = (currentIndex + 1) % positions.length;
    const currentPosition = positions[currentIndex];

    const perpendicularPoint = calculatePerpendicularPoint(currentPosition);
    
    // Increment the entity ID counter for a unique ID
    const movingLineEntityId = `movingLineEntity_${entityIdCounter++}`;

    // Create a new moving line entity with the incremented ID
    const movingLineEntity = viewer.entities.add({
        id: movingLineEntityId, // Assign a unique ID
        polyline: {
            positions: [currentPosition, perpendicularPoint],
            width: 3,
            material: Cesium.Color.BLUE
        }
    });

    // Update the model's position after a short delay
    setTimeout(() => {
        modelEntity.position = currentPosition;
    }, 60); // Delay for 60ms to avoid blocking

    // Remove the previous moving line entity that was left behind
    const previousMovingLineEntityId = `movingLineEntity_${entityIdCounter - 2}`;
    if (viewer.entities.getById(previousMovingLineEntityId)) {
        setTimeout(() => {
            viewer.entities.removeById(previousMovingLineEntityId); // Remove by ID
        }, 70); // Delay with a buffer of 10ms, doesn't take as long but still needs it
    }
}

// Use setInterval to move the model to the next position every second.
setInterval(updatePoint, 1000);

The creation of the Polyline appears to only block the camera position update, not the update of anything else in the view, which would explain why the flicker only happens when tracking.

Next, I will try offsetting the polyline updates and the model position updates so that they never happen at the same time, I hope that will be a better way to workaround the issue.

(I’m still hoping that someone will chime in here and confidently say: “THIS is how it’s done!” and post a solution - in the meantime, my best efforts here:)

That approach of adding and removing entities based on a setTimeout is almost certainly not ideal. For me, the flickering was even worse, and twiddling with delays of 60 and 70 ms (and wondering whether it should be 61 and 69) sounds brittle.

I had a short look at the issue that you linked to. And it seems … somewhat related insofar that the flickering seems to be connected to the trackedEntity. When omitting that in the sandcastle that is shown in the issue, then it also does not flicker. (This is just an observation, but… the plot thickens: Maybe there’s something wrong with the trackedEntity handling…)

But more generally, and as you already found out: The usual approach for this sort of updates is to not use something.position = newPosition;, but to use a CallbackProperty instead.

I already mentioned that I think that the model entity should use a CallbackProperty. And you already mentioned that you tried using a CallbackProperty for the polyline:

Here is a sandcastle that uses a callback property to update the position of the perpendicular line, and that does fix it, but you can see the performance issues that are caused by the CallbackProperty when you crank up the number of points in the perpendicular line. That’s because CallbackProperty gets called every single frame, and Cesium cant handle redrawing the polyline every single frame even for a relatively modest number of points like 1000.

I think that the main problem can easily be avoided here: You correctly said that the CallbackProperty is called each and every frame. And you should definitely not do any costly computations there. But … you don’t have to re-compute the positions every frame. You only have to return them every frame. Computing them can still be done every 1000ms.

Here is an updated Sandcastle. (Parts of this could be “cleaned up” a bit - but I tried to do “the minimal modifications that are necessary to demonstrate the approach”).

It defines two callback properties:

  • One for the model position. The position that this property returns is updated in updatePoint, every 1000ms
  • One for the positions of the perpendicular line. The positions array that is returned by this property is also only computed in updatePoints, every 1000ms. (So when the property is queried each frame, it will always return the same set of points - until the points are updated explicitly in updatePoints).

It contains a console.log("Recomputing") for when the expensive computation of the new points is done. And this is printed only once per second.

So you can decide upon the “update frequency” via the setTimeout. I tried it with setInterval(updatePoint, 50); and it seems to move smoothly and without flickering. (Of course, if the computation of the new points takes more than 50ms, you have to decrease the update frequency - this has to be sorted out…)

Using a callback property still doesn’t fit my performance needs, the CallbackProperty performance is relatively poor even if the only thing you do on the scene is draw a line with a CallbackProperty and never change anything. Here is a Cesium Sandcastle for that, I have a very beefy MacBook Pro and notice lower FPS at 10,000 points, but 100,000 points results in a complete slow down of the entire browser (Without CallbackProperty I can make it to 1 Million points before noticing a modest FPS drop).

I managed to find a workaround that is mostly acceptable, I believe my suspicion that the updating of the Polyline is blocking the camera position update is correct. So, I simply wrap updating the Polyline positions in a setTimeout and set the delay to 50ms which keeps that blocking from happening at the same time the camera is trying to move.

    setTimeout(() => {
      movingLineEntity.polyline.positions = [currentPosition, perpendicularPoint];
    }, 50);

(cesium sandcastle here)

There is still a brief flicker for the line, because of the delay, and while not perfect, is much more acceptable than the model/camera jump flicker thing that was happening in my original cesium sandcastle.

This issue only happens when updating polylines, if i update another model at the same time the issue does not happen.

About the performance drop: That is known to some extent, via Polygon + property callback = dramatic performance drop · Issue #10946 · CesiumGS/cesium · GitHub , going back to a looong standing issue at Dynamic Buffers · Issue #932 · CesiumGS/cesium · GitHub

In your case, it seemed like the main reasoning for using the CallbackProperty for the polyline was to avoid the flickering. In the last sandcastle, there indeed is only a slight flickering of the line. But it’s still unfortunate that this kind of workaround is necessary.

I’ve seen your comments in Weird interaction between CzmlDataSource.process and tracked entity · Issue #4647 · CesiumGS/cesium · GitHub - let’s hope that someone can allocate some time to investigate that one further. It might be tricky, because it seems to be very specific for the combination of polylines and a trackedEntity, but maybe someone already has a hunch what might be wrong there…

1 Like

Ensure that the camera follows the model using Scene.preRender events. This way, the camera and model are updated in sync before each frame is rendered, avoiding the desynchronization that causes the flicker.

viewer.scene.preRender.addEventListener(function(scene, time) {
var modelPosition = modelEntity.position.getValue(time);
viewer.camera.lookAt(modelPosition, new Cesium.Cartesian3(0, 0, 10));
});

1 Like

I investigated was able to find and fix the problem in the Cesium source code. It was indeed very subtle and tricky to pin down. Both the sand castle in this forum post and the sandcastle in Issue #4647 will be fixed in the next release.

Thank you both Marco and Hamza for your time and efforts.