Changing ImageryProvider randomly obscures existing billboards and labels

Hi, When I change the Map provider, the existing billboards and labels are then randomly semi-obscured as if rendering the new tiles interferes with who is on top. Sometimes it only happens when one zooms in or out of the globe....
Do I need to put in the CompositePrimitive raiseToTop code - then please show me how - do I raise the entire BillboardCollection? Sandcastle code follows.
Many thanks!
Regards
Rencia

require(['Cesium'], function(Cesium) {
    "use strict";

    var widget = new Cesium.CesiumWidget(‘cesiumContainer’, {
        imageryProvider : new Cesium.ArcGisMapServerImageryProvider({
            url : ‘http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer
        })
    });

    var layers = widget.centralBody.imageryLayers;

    var ellipsoid = widget.centralBody.ellipsoid;
    var scene = widget.scene;
    var primitives = scene.primitives;

    var image = new Image();
    image.onload = function() {
        var billboards = new Cesium.BillboardCollection();
        var textureAtlas = scene.context.createTextureAtlas({
            image : image
        });
        billboards.textureAtlas = textureAtlas;

        billboards.add({
      position : ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-75.59777, 40.03883)),
      imageIndex : 0
         });
            scene.primitives.add(billboards);
        };
        image.src = '../images/Cesium_Logo_overlay.png';
    
    function changeMap(layers){
    var provider = new Cesium.TileMapServiceImageryProvider({
            url :'../../../Source/Assets/Textures/' + 'NaturalEarthII'
    });
    try{
            layers.removeAll();
        }catch( e){
        }
        layers.addImageryProvider(provider);
        widget.centralBody.depthTestAgainstTerrain = true;
    }
    
    Sandcastle.addToolbarButton('changeMap', function() {
        changeMap(layers);
     });

    Sandcastle.finishedLoading();
});

Hi,

Changing the base imagery layer causes Cesium to re-refine the terrain surface (or the ellipsoid surface if you’re not using terrain) from the low-resolution root. The end result is that the surface may appear to move up or down relative to other objects placed near the surface until the imagery down to the level you’re looking at has been fully loaded. If you’re seeing a change in obscuration after the new layer is done loading, though, then you may be seeing a different problem.

Kevin

Thanks Kevin, will do more testing & see if the problem persists after some passage of time…

Thanks Kevin, will do more testing & see if the problem persists after some passage of time....

Hi Kevin, nope, obscuration persists. When move the graphic around, the billboards and labels surface and semi-obscure randomly .... even 10 minutes later.

Any ideas?
Thanks
Regards
Rencia

> Thanks Kevin, will do more testing & see if the problem persists after some passage of time....
>
>
>

>
> Hi Kevin, nope, obscuration persists. When move the graphic around, the billboards and labels surface and semi-obscure randomly .... even 10 minutes later.
Any ideas?
Thanks
Regards
Rencia
>

Hi, have just upgraded to b28, sorted some other issues but this one is a bit worse. I see that in b29 coming is "Improved terrain and imagery rendering performance when very close to the surface" - might that solve my problem?

See sandcastle code below. Obscuration now happening right from the start, not only after change base imagery layer. My real billboards are much smaller than this image so I lose them entirely.... Commenting out the depthTestAgainstTerrain on line 31 solves it for the billboards but then the ellipsoid and ellipsoidOutlineGeometry doesn't work properly when under the surface. See my other post
https://groups.google.com/forum/embed/?place=forum%2Fcesium-dev&showsearch=true&hideforumtitle=true&parenturl=http%3A%2F%2Fcesiumjs.org%2Fforum.html&theme=default#!topic/cesium-dev/ZCzBQsDALD0

Many thanks.
Rencia

Oops, here is my code:
require(['Cesium'], function(Cesium) {
    "use strict";

    var handler;
    var label;
    var billboard;

    function addBillboard(scene, ellipsoid) { //, image) {
            var image = new Image();
            image.src = '../images/Cesium_Logo_overlay.png';

            var billboards = new Cesium.BillboardCollection();
            var textureAtlas = scene.createTextureAtlas({
                image : image
            });
            billboards.textureAtlas = textureAtlas;
            billboard = billboards.add({
                position : ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-75.59777, 40.03883)),
                imageIndex : 0
            });
            billboard.isBillBoard = true;
            scene.primitives.add(billboards);
    }

    var widget = new Cesium.CesiumWidget('cesiumContainer');

    var scene = widget.scene;
    var ellipsoid = scene.globe.ellipsoid;
        
    scene.globe.depthTestAgainstTerrain = true; //so that shapes UNDER the surface are not visible

    addBillboard(scene, ellipsoid);

    Sandcastle.finishedLoading();
});

Hi,

Since you’re not specifying a height in the call to Cesium.Cartographic.fromDegrees, Cesium uses a height of 0.0 meters, relative to the WGS84 ellipsoid. In most cases, that’s underneath the terrain surface.

You can use the sampleTerrain function to compute the height of terrain at a given list of longitude/latitudes.

http://cesiumjs.org/Cesium/Build/Documentation/sampleTerrain.html?classFilter=sample&show=js

It’s also a good idea to set the billboard’s verticalOrigin property to Cesium.VerticalOrigin.Bottom. Otherwise, half of the billboard will still be below terrain.

Kevin

Only seeing this now ... Thanks Kevin! Will give those a bash.
Regards
Rencia

Kevin, any chance you could advise me on my other issue. Have excluded 2D for the moment because of it but REALLY want it back!
See

https://groups.google.com/forum/embed/?place=forum%2Fcesium-dev&showsearch=true&showpopout=true&hideforumtitle=true&parenturl=http%3A%2F%2Fcesiumjs.org%2Fforum.html&afterlogin=#!topic/cesium-dev/ZCzBQsDALD0

Many thanks!

Regards

Rencia

Hi Kevin, have switched on the notification in google mail now, so it notifies me when emails arrive!!
I tried the terrainprovider you suggested - not much success - then I switched off my depthTestAgainstTerrain and voila!! Works.

However I also need that depthTest on account of the ellipsoids …

Below is my sandcastle code, draws billboard, polygon & ellipsoid - if you comment / uncomment the depthTestAgainstTerrain on line 12, you will see what I mean. Zoom in & out when it it is on and you see how the polygon & billboard disappear/appear.

We need the ellipsoid to be cut off at the earth/sea surface. If we use it to surround for eg. an object rising from the surface, it gradually reveals more until when the object is higher than the diameter, you will see the whole ellipse.

How can I chop off the portion of the ellipsoid below the surface? Or should I be using an entirely different object altogether? Remember that the ellipsoid also needs to move position with the object… (For the movement - Dan gave me the solution to seperate out the modelmatrix - which causes the 2D to fail, but 3D moves easily)

Summary of issues desperate for help:

  1. Visibility of billboards, polylineCollections, labels and polygons VERSUS hiding ellipsoid portion below surface

  2. Moving ellipsoid but still keeping 2D integrity …

Please help. Thanks!

Regards

Rencia

Code:

require([‘Cesium’], function(Cesium) {

“use strict”;

var widget = new Cesium.CesiumWidget(‘cesiumContainer’, {

imageryProvider : new Cesium.OpenStreetMapImageryProvider({

url : ‘http://otile1.mqcdn.com/tiles/1.0.0/osm

})

});

var scene = widget.scene;

//scene.globe.depthTestAgainstTerrain = true;

var primitives = scene.primitives;

var ellipsoid = scene.globe.ellipsoid;

var terrainProvider = new Cesium.CesiumTerrainProvider({

url : ‘//cesiumjs.org/smallterrain

});

var billboard;

function addBillboard(scene, ellipsoid, terrainProvider) { //, image) {

var image = new Image();

image.src = ‘…/images/Cesium_Logo_overlay.png’;

var positions = ellipsoid.cartographicArrayToCartesianArray([

Cesium.Cartographic.fromDegrees(18.06, -32.65)

]);

var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);

Cesium.when(promise, function(updatedPositions) {

var billboards = new Cesium.BillboardCollection();

var textureAtlas = scene.createTextureAtlas({

image : image

});

billboards.textureAtlas = textureAtlas;

billboard = billboards.add({

position : positions[0],

imageIndex : 0,

verticalOrigin : Cesium.VerticalOrigin.BOTTOM

});

billboard.isBillBoard = true;

scene.primitives.add(billboards);

});

}

function drawPoly(terrainProvider, primitives) {

// Red polygon

var positions = ellipsoid.cartographicArrayToCartesianArray([

Cesium.Cartographic.fromDegrees(17.96, -32.65),

Cesium.Cartographic.fromDegrees(18.06, -32.75),

Cesium.Cartographic.fromDegrees(18.37, -32.67),

Cesium.Cartographic.fromDegrees(17.97, -32.56)

]);

var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);

Cesium.when(promise, function(updatedPositions) {

var redPolygonInstance = new Cesium.GeometryInstance({

geometry : Cesium.PolygonGeometry.fromPositions({

positions : positions,

vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT

}),

attributes: {

color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.2))

}

});

// Add polygon instances to primitives

primitives.add(new Cesium.Primitive({

geometryInstances : redPolygonInstance,

appearance : new Cesium.PerInstanceColorAppearance({

closed : true,

translucent : true

})

}));

});

}

function drawDome(scene, ellipsoid, terrainProvider) {

// Create ellipsoid are position with model matrix

var height = -2500.0;

var positions = ellipsoid.cartographicArrayToCartesianArray([

Cesium.Cartographic.fromDegrees(18.06, -32.60)

]);

var radii = new Cesium.Cartesian3(5000.0, 5000.0, 5000.0);

var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);

Cesium.when(promise, function(updatedPositions) {

var ellipsoidmodelMatrix = Cesium.Matrix4.multiplyByTranslation(

Cesium.Transforms.eastNorthUpToFixedFrame(positions[0]),

new Cesium.Cartesian3(0.0, 0.0, height)

);

var ellipsoidGeometry = new Cesium.EllipsoidGeometry({

vertexFormat : Cesium.VertexFormat.VERTEX_FORMAT,

radii : radii

});

var ellipsoidInstance = new Cesium.GeometryInstance({

geometry : ellipsoidGeometry,

//modelMatrix : ellipsoidmodelMatrix,

id : ‘dome’,

attributes : {

color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 0.0, 1.0, 0.4))

}

});

// Add ellipsoid instance to primitives

var domePrimitive = new Cesium.Primitive({

geometryInstances : ellipsoidInstance,

id : ‘dome’,

appearance : new Cesium.PerInstanceColorAppearance({

translucent : true//,

//closed : true

})

});

domePrimitive.modelMatrix = ellipsoidmodelMatrix;

scene.primitives.add(domePrimitive);

});

}

Sandcastle.addToolbarButton(‘Draw polygon’, function() {

//cleanup();

drawPoly(terrainProvider, primitives);

});

Sandcastle.addToolbarButton(‘Draw billboard’, function() {

//cleanup();

addBillboard(scene, ellipsoid, terrainProvider);

});

Sandcastle.addToolbarButton(‘Draw dome’, function() {

//cleanup();

drawDome(scene, ellipsoid, terrainProvider);

});

var destination = Cesium.Cartographic.fromDegrees(18.06, -32.70, 25000.0);

var flight = Cesium.CameraFlightPath.createAnimationCartographic(scene, {

destination : destination

});

scene.animations.add(flight);

Sandcastle.finishedLoading();

});

Hi,

I would try leaving depthTestAgainstTerrain on, and then put your billboard a bit above the terrain surface. Adding one meter should do the trick.

Kevin

Hi Kevin, nope I tried that, went as high as 10m, still the obscuration persists. Thats when I started posting to you guys…
Its turning out a bit tricky to keep using the terrainprovider, the polygon keeps changing so have to store the points, going back and forth between java & javascript… isn’t there some way I can chop that ellipsoid for the dome in half?

Sorry to be a nuisance!

Thanks

Rencia

Hi Kevin, What about a depthTest Setting attached to a specific object only not the whole globe? How difficult would that be to implement?
Thinking out loud…

R

Hiya, Been thinking all day about that depthTest. When its set to true, the graphics render more slowly, objects flicker - eg. polylineCollections come and go as you zoom in & out.

I implemented the code to use the sampleTerrain Setting that you suggested for the obscuration - using a brief sampling of the objects I am using, - running in the sandcastle - a fantastic tool by the way!

Thats the code I posted above. Could not get it to work the way you suggested, but maybe I am doing it incorrectly? I so appreciate that you must be busy people - and doing this opensource on the side; but would muchly appreciate you having a look at that code …

But if depthTestAgainstTerrain = false; presto, MUCH more dynamic response from the graphics! And no obscuration!

SO - it seems to make sense that if one places a filter like that on the rendering of every object - they would take longer, having to be re-interpreted with every zoom of the mouse! and after thousands of objects - which we still need to simulate, the response might decay more.

The obscuration of the objects is the more pressing problem though because that could affect the human interpretation of the information, certainly the ease of its use.

SO, I am imagining adding a depthTest to only a certain specific instance of an object say THIS ellipsoid+ellipsoidOutline.

I will do a search on the cesium.js to see if I can find a reference to your actual code that does exactly that - but seperating it from its context to extract only that kernel is a daunting task and will take much time. I would very much appreciate it if you could isolate the code FOR me that actually evaluates & sets occlusion on a specific object. Do you think what I suggest is possible? Is it as easily done as I imagine?

If I had the actual code fragment it would make it so much easier to incorporate into my code that constructs or moves the graphic representation of the object.

Even more excellent if you added it as say an attribute… but i need it real soon, like midweek next week if possible. So perhaps quicker if for mow I just added it to the code that constructs & moves the object…

What do you think?

Thanks.

Rencia

Hi Kevin, any further info on the depthtest versus sampleTerrain? Thanks.

Hi Rencia,

That’s suspicious that turning off the depth test improves performance. Perhaps surprisingly, turning off the depth test results in Cesium doing more work, not less. Specifically, after it renders terrain, it issues an additional command to clear the depth buffer before rendering the rest of the graphics. This is also the reason that we can’t control depth testing per primitive: once the depth buffer is cleared, it is not available for use by any primitives. It’s possible to leave the depth buffer intact but disable depth testing for individual primitives, but then primitives on the back side of the globe are visible, too (and possibly other rendering artifacts).

The obscuration at different zoom levels is probably caused by the changing level of detail of the terrain surface. You may be able to solve or at least reduce this by moving the object higher (even higher than 10 m) above the terrain surface. But mostly this is a tough problem, and it’s one that we’ll solve eventually but not extremely soon. In the meantime, one way to deal with surface-conforming geometry is to rasterize it. Import your vector data into something like Geoserver and then serve it to Cesium as a WMS imagery layer.

Kevin

Thanks Kevin. Will play around a bit more then.
Regards

Rencia