Canvas Dom Element as Imagery provider question.

Hey guys, I have created a HeatMapImageryProvider which uses the vector features on the globe to render a heatmap onto a canvas which is then wrapped onto the globe. This works great and all, however, when I make updates to the canvas, I cannot get the image on the globe to update without removing the imageryprovider and re-adding it. I have read that webgl can render dynamic dom elements like canvas and videos and accept updates, but I don’t know if there is something I need to be doing differently or something that needs to happen in the Cesium rendering code to make this happen.

I have posted my work so far for the HeatMapImageryProvider here if you guys care to take a look. Currently it only works with OpenLayers feature objects, but I can modify it to take the cesium primitives collection instead if you guys want to have it. The only problem with that is, Cesium currently has no eventing system like OpenLayers, so the imageryprovider has no idea when a primitive is added to know when to update/redraw the heatmap.

So My question was, would anyone happen to know how let webgl know that the canvas texture was updated? I guess I thought this would be the default behavior and it would automatically update, but doesn’t seem to be the case.

Also, here is a cool screenshot of a heatmap in Cesium of F-4 and F-5 tornados accross the united states since 1950.

Well, WebGL doesn’t have any way, to my knowledge, to automatically re-upload a texture when a backing canvas is updated. The imagery system we have currently assumes that once a tile loads, it never changes, so we don’t currently have a way to invalidate tiles or force them to be reloaded.

We probably should add some API for this, but in the meantime, you should be able to get it to reupload the texture manually. Since you only have one tile, this is simpler.

Basically, when you redraw the canvas, you should set the ImageryState of the Imagery that contains your single imagery tile back to UNLOADED, which will make the update loop call requestImage again, where you can return the same canvas reference as always.

To do this, on the ImageryLayer that contains your provider, call getImageryFromCache(0, 0, 0), which should give back the Imagery object, then set imagery.state = ImageryState.UNLOADED.

Hopefully that works, if not, let me know and I can investigate more.

Thanks for the help Scott. That works! Sometimes the tile is not re-requested though until I pan or zoom the camera. Is there something I can call to force the imagery layer to re-render? I tried to call update() in scene, but it doesn’t trigger the tile request. I’m still investigating a way to do it. Any ideas?

After looking at the implementation a bit more, there’s a doneLoading flag on the tile that is used as an optimization to avoid checking the tileState against a list of possibilities, so we need to reset that flag to force the system to check the states again.

The easiest way to iterate the tiles is to use the replacement queue, which contains all loaded tiles, instead of trying to traverse down the quadtree of tiles. This will need to use some “private” fields, at least until we add better APIs for this.

Given the central body, and the Imagery object that you got from the cache earlier, do:

// assuming variables “centralBody” and “imagery” already defined

var tile = centralBody._surface._tileReplacementQueue.head;

while (typeof tile !== ‘undefined’) {

var tileImageryCollection = tile.imagery;

for (var i = 0, len =
tileImageryCollection.length; i < len; ++i) {

// we only need to reset the flag for Tile objects that overlap the

// Imagery object that we are updating, that is, tiles that have a

// TileImagery object that references the Imagery object.

if (tileImageryCollection[i].imagery === imagery) {

tile.doneLoading = false;

break;

}

}

tile = tile.replacementNext;

}

Let me know if that works for you. The inner for loop and if check is an optimization, if you have trouble, try taking it out, and just setting every tile.doneLoading to false.

Scott

Thanks again Scott, that works great! It is much smoother and the performance is much better than adding and removing the entire layer on each update.

Does this still work? Is there a way to get an animated heatmap for Cesium?
The examples on: https://github.com/jktaylor/openlayers/wiki didn’t seem to work and I wonder if it was due to some update or something.

I’m super interested in an animated heatmap on top of Cesium…