Cesium heavy rendering

I’ve put a small example online, and saw some heavy rendering going on, making my computer freeze.
Here’s the sample code (you can just paste it to sand castle):

function generateCoordinates(radius, centerLong, centerLat){
var r = radius/111300 // = 100 meters
, y0 = centerLat
, x0 = centerLong
, u = Math.random()
, v = Math.random()
, w = r * Math.sqrt(u)
, t = 2 * Math.PI * v
, x = w * Math.cos(t)
, y1 = w * Math.sin(t)
, x1 = x / Math.cos(y0);

      var newPos = ({latitude: y0 + y1, longitude: x0 + x1});
      return new Cesium.Cartesian3.fromDegrees(newPos.longitude * 180/Math.PI, newPos.latitude * 180/Math.PI);
    }
   
    function addEntity(params, collection){
        var entity = collection.getOrCreateEntity(params.id);
        var keys = Object.keys(params);
        keys.forEach(function(value){
            if (value != 'id')
                entity[value] = params[value];
        });
    }
   
    function getRandomId(){
      return ids[Math.floor(Math.random()*ids.length)];
    }
   
    function addOrUpdateEntities(n){
      entities.suspendEvents();  
     
      for (var i = 0; i < n; i++){
        ids.push(i);
        params = {
            id: i,
            position: generateCoordinates(100000, startingLocation.centerLong, startingLocation.centerLat),
            label: {
                text: i.toString(),
                font: '8px sans-serif'
            },
            billboard: {
                image: pinBuilder.fromColor(Cesium.Color.ROYALBLUE, 48).toDataURL(),
                width : 32, // default: undefined
                height : 32 // default: undefined
            }
        };
        addEntity(params, entities);
      }
      entities.resumeEvents();    
    }
   
    var pinBuilder = new Cesium.PinBuilder();

var vm = {};
var params;

    vm.cesium = new Cesium.Viewer(cesiumContainer, {
      baseLayerPicker: false,
      fullscreenButton: false,
      homeButton: false,
      sceneModePicker: false,
      selectionIndicator: false,
      timeline: false,
      animation: false,
      geocoder: false
    });
   
    var entities = vm.entities = vm.cesium.entities;
    var randomImage;
   
    var n = 10000; //number of starting entities
    var id, params;
    var ids = [];
   
    //Grand Island, Nebraska in radians
    var startingLocation = {
        centerLong: (-98.343286 * Math.PI / 180),
        centerLat: (40.923664 * Math.PI / 180)
    };
   
    vm.cesium.camera.flyTo({
        destination: new Cesium.Cartesian3.fromDegrees(startingLocation.centerLong * 180/Math.PI, startingLocation.centerLat * 180/Math.PI, 5000000)
    });
   
   
    addOrUpdateEntities(n);

``

I attach images that show the amount the rendering cycle takes - more than 90% of the time, the app is rendering. When I tried to measure using the timeline tool, the app was way below 60Hz (more like 10Hz at best). I’ve checked this on a stronger (offline) computer, while this (online) computer just crashed every time I tried the timeline tool.

Am I doing something wrong in the handling of entities here?

Hello,

The example you posted rendered for me in about 4 seconds.

What are your computer specs? I have a pretty good NVIDIA card in this computer, so that might be why it’s rendering quickly for me.

Best,

Hannah

It’s not the rendering itself. if it was only the first rendering it would have been fine, but I’m getting the whole computer hanging just by the app being on screen. I don’t even try to interact with it in any way.
It seems that cesium’s rendering cycle works constantly and chokes up the JS thread just by having billboards/labels in it.

What I see is the recursive rendering that chokes up the system. Every tick it renders the whole primitive tree in the scene, for billboards it’s like 2N at best, which is quite wasteful…

Can you turn on the js profiler in dev tools and see it?

Ah, sorry for misunderstanding. Yes, I am seeing the same results in the profiler, but the application doesn’t bog down my computer the way you’re saying it’s effecting yours.
This is a little outside my realm of knowledge, but maybe someone else will have a suggestion.

Thanks,

Hannah

Hi Yonatan,

This runs OK on my machine. I took a quick look at this in the profiler. 10,000 entities is a lot - and is burning a lot of CPU. Perhaps try using the primitive API directly for billboards and labels.

Patrick

Yonaton, can you copy and paste the results of going to webglreport.com from the machine that locks up? This sounds like it could be a driver issue and you’re possibly falling back to software rendering. Make sure your machine has the latest available drivers. Can you also provide the OS, browser, and video card you are using (all with version information).

While there is certainly lots of room for improvement in how static Entity billboard and labels are rendered, there’s no reason you should be seeing the poor performance you are getting… Do demos like http://apps.agi.com/SatelliteViewer/ work for you? (Hit the green x on the left to show all 15k entities). Is your actual use case for static data or dynamic data?

One possible tweak you can make is to not show labels all of the time but instead only show them for the selected entities or somehow specified group of entities. That would dramatically improve performance.

Finally, while not directly related to your issue, the way you are adding entities is vary odd. You can get rid of your addEntity function and just replace it with a call to entities.add.

entities.add({
    id: i,
    position: generateCoordinates(100000, startingLocation.centerLong, startingLocation.centerLat),
    label: {
        text: i.toString(),
        font: '8px sans-serif'
    },
    billboard: {
        image: pinBuilder.fromColor(Cesium.Color.ROYALBLUE, 48).toDataURL()
    }
});

Thanks Patrick.
How would using the primitives help? What clamps my app is the
primitiveCollection.update method (i.e. billboardCollection.update). Is
this constantly working even when there's no update because of the dynamic
nature of entities?
Thanks

Thanks Matthew.

I know windows 10 overrides NVidia’s own driver updates sometimes, which might cause some kind of conflict.

webgl 2.0 isn’t supported according to that site. Is that reason for concern?

The demo worked fine though… I do have a need to show a label for every billboard (that’s part of the specs of the app). I could create the billboard’s SVG dynamically with the words/numbers canvas and attach them together. That should take down the load in about 50%, right?

Is there a way to "reuse’ labels that are the same? I might have 10,000 entities but most of them are the same (e.g. A billboard that represents a MacDonald drive in, would have MacDonald near it, while Pizza Hut would have its own label - but each time it’s the same canvas for every MacDonald and for every Pizza Hut. The labels themselves aren’t dynamic (they remain mostly the same). Billboards are a bit more dynamic in the app.

While your last point is not related, since the heavy load remains after the entities were added to the map, it is an interesting point.I’m using this odd method because I sometimes add a new billboard, but sometimes I just update a new one. (e.g. setInterval(function(){addOrUpdateEntities(Math.round(Math.random()*nUpdate));}, 1000)). In addition, my function only updates the necessary params - so if an entity has multiple graphics, only what’s sent in the params changes. Here it’s not so dynamic but in my app I have entities with multiple graphics (e.g. a billboard inside a poylgon) and sometimes only their coordinates change, but sometimes they change the image, color, ellipse axes etc…

Is there some benefit in updating only the relevant parameters of an existing entity? Is there a performance issue adding billboards this way? Should I separate creation from update? I assumed, since “entitiyCollection._entities” is an associative array that the “getOrCreate” is much the same as “get” when we already have this entity in the collection.

Thanks.