Speeding up billboard updates

I'm working on a Cesium based geospatial data viewer that works primarily in 2D. To visualize vector fields on a map, we use billboards. The arrow image is swapped based on the magnitude of the vector, and the whole billboard is rotated based on the direction of the vector.

These vector fields can be very large (>100,000) elements, and are expensive to update. Basically, this is the loop that runs every time the visualization updates:

for (var uv = mag_data.length; uv--:wink: {
    //billboards[uv].show = true;
    billboards[uv].rotation = dir_data[uv];
    billboards[uv].image = this._images[this.getImageIdx(mag_data[uv])];
    billboards[uv].mag = mag_data[uv]; //metadata for use elsewhere
    billboards[uv].dir = dir_data[uv];
}

This loop is expensive, but what is more expensive is what comes afterwards, when the Cesium viewer is pushing these changes to the graphics card. (In particular, the `BillboardCollection.update` function) Are there any things I could do to speed this second step up?

Would batching the billboards into separate smaller primitives help at all?

Try using the setImage function instead, which is designed for this purpose:

https://cesiumjs.org/Cesium/Build/Documentation/Billboard.html#setImage

Basically, you’ll want to come up with your own naming scheme for each of the arrow images. From your existing code, probably the result of getImageIdx is sufficient, but you can use anything that produces a unique string per image and also contains enough information to locate or reconstruct the image, which is what the function you pass in will do.

The result is that switching images will only need to change the pointer into its internal texture atlas. Your existing code forces the billboard collection to recreate the texture for every arrow every time, because it has no way to know if the Image object has changed or not.

Thanks for the reply Scott. I tested your suggestion and I found it slightly slower than setting the image attribute directly. To give some more background on the images, they (~30 of them) are generated when the BillboardCollection is first instantiated via being drawn to a canvas, then assigned to a new Billboard in order to create the texture (and I assume add it to the BillboardCollection's texture atlas). The image ID is then stored in an array as a string (what getImageIdx references into). All new Billboards from this point will only use one of those 30 initial images.

I think that it's already using the internal texture atlas and also skipping the two !defined checks that setImage has to do, so it's slightly faster.

(Here’s a blog post with some background on this topic.)

Since you have a set number of images, perhaps create a new billboard collection “batch”/“pool”/etc for each type and assign their positions during the update, rather than updating the image at each position? It’s cheaper to update the instanced position than it is to update the images.

Thanks,

Gabby

I think I know what you mean, but there are too many arrow sizes to make that viable.

For some idea of the scope of the problem, we're bumping into performance limits at ~100k vectors, with 30-40 arrow sizes. Each pool unfortunately would have to be of size N, which makes (I think) a prohibitive number of billboards hanging around.

Are there any scene or global configuration options that could help, or are we bumping up against Billboard architectural limits at this point?

I had problems with boxes updating slow.
http://www.youtube.com/watch?v=TnMFpKqE0SI&t=0m24s (thats a six time
speed update) The box always hang after the label.

gltf and glbs are updated much quicker.

Thanks for the suggestion, Ankhenaten!

Jay, there’s an issue open in GitHub, #2319, that I think would help. I’ll bump that issue with this report.