Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Billboards with CLAMP_TO_GROUND don't like being dragged #3488

Closed
hpinkos opened this issue Jan 28, 2016 · 2 comments
Closed

Billboards with CLAMP_TO_GROUND don't like being dragged #3488

hpinkos opened this issue Jan 28, 2016 · 2 comments

Comments

@hpinkos
Copy link
Contributor

hpinkos commented Jan 28, 2016

There's an error in drawing billboards that are clamped to ground when their position updates a whole bunch. billboard.position will have the correct position, but the billboard will occasionally jump around on the screen when you zoom in and out.

@mramato suspected there is a race condition somewhere in our clamp to ground computation. The position value might change while clamp to ground is being computed, and it ignores the change.

@bagnell any ideas?

Here's an sandcastle example for reproducing the bug:

  1. Drag one of the billboards around all over really really quickly
  2. Zoom in and out once you stop dragging. The dragged billboard will jump around to a few different positions.
var viewer = new Cesium.Viewer('cesiumContainer', {
    baseLayerPicker: false,
    terrainProvider: new Cesium.CesiumTerrainProvider({
        url : '//assets.agi.com/stk-terrain/world',
        requestWaterMask : true,
        requestVertexNormals : true
    })
});
var lon = -110.45;
var lat = 37.9;
var billboardCollection = viewer.scene.primitives.add(new Cesium.BillboardCollection({
    scene : viewer.scene
}));

for (var i = 0; i < 5; i++) {
    billboardCollection.add({
        image: '../images/facility.gif',
        position: Cesium.Cartesian3.fromDegrees(lon + i * 0.001, lat),
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
    });
}

var dragging;
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);

handler.setInputAction(function(click) {
    var pickedObject = viewer.scene.pick(click.position);
    if (Cesium.defined(pickedObject)) {      
        dragging = pickedObject;
        viewer.scene.screenSpaceCameraController.enableRotate = false;
    }
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);

handler.setInputAction(function() {
    if (Cesium.defined(dragging)) {
        dragging = undefined;
        viewer.scene.screenSpaceCameraController.enableRotate = true;
    }
}, Cesium.ScreenSpaceEventType.LEFT_UP);

handler.setInputAction(function(movement) {

    var ray = viewer.camera.getPickRay(movement.endPosition);
    if (Cesium.defined(dragging)){
        var position = viewer.scene.globe.pick(ray, viewer.scene);
        if (Cesium.defined(position)){
            dragging.primitive.position = position;
        }
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(lon + 3* 0.001, lat, 2000)
});
@hpinkos
Copy link
Contributor Author

hpinkos commented Jan 29, 2016

So, with some investigating, I think I figured out what is happening:

Billboard calls QuadtreePrimitive.updateHeight whenever the position is changed. This adds a callback function to every tile, so when that tile is updated it update the billboard.
QuadtreePrimitive.updateHeight returns a function to remove the callback. Billboard calls this remove function every time the position changes. So there theoretically shouldn't be updates made based on outdated positions,

However, I don't think the callback is being removed from every tile it was added to.
When the remove function is called, it appends to the QuadtreePrimitive._removeHeightCallbacks list, which is used in selectTilesForRendering. I don't think the loop that removes the callbacks loops through all of the tiles it was added to
As a result the billboard's callback to update the position is called with the wrong data

And this is where I'm stuck because I don't know how to fix the loop so that it removes the callback from all the right tiles.
@bagnell?

@hpinkos
Copy link
Contributor Author

hpinkos commented Jan 29, 2016

I did code a workaround that fixes the bug by ignoring the callback if it's not the latest position and pushed it to the billboardClampToGroundBug branch.
Setting breakpoints here helped me figure out that it's an issue with the QuadtreePrimitive. In case that's useful:
https://github.com/AnalyticalGraphicsInc/cesium/blob/billboardClampToGroundBug/Source/Scene/Billboard.js#L850

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant