Dynamically updating Billboard textures - memory leak?

1,209 views
Skip to first unread message

Mark Erikson

unread,
Nov 13, 2014, 3:05:09 PM11/13/14
to cesiu...@googlegroups.com
We've got some Billboards that we're using to show coordinates by drawing to a canvas and assigning that as the Billboard's image.  Previously, we were creating a new canvas every time.  I changed our code to create a canvas once, and clear it and redraw as necessary.  That didn't seem to work by itself.  After digging through the Billboard source, I concluded that you actually have to re-assign to Billboard.image to trigger an update.  That fixed the immediate issue.

However, I'm a bit concerned about what I think I'm seeing with the Billboard and TextureAtlas implementation.  As best as I can tell, TextureAtlas has no provision for removing or updating existing images.  If that's the case, it seems that continually modifying Billboard images is going to result in the TextureAtlas repeatedly growing its internal texture, and ultimately it's almost going to be a sort of memory leak.  Is that the case, or is there something about the implementation that I'm missing?

It seems like it would be useful to have a couple new abilities for TextureAtlas and Billboard.  Right now, Billboard.setImage() ignores an attempt to use the same image ID.  It would be nice to allow updates to a given image ID.  If the new image was the same dimensions, simply overwrite the existing region in the TextureAtlas.  Then, give TextureAtlas the ability to remove or mark regions as unused, and either reuse them later, or skip them when doing a texture resize.  I do realize that the latter would involve some pretty involved changes to the texture node algorithm, but there's obviously plenty of 2D bin packing algorithms out there that could be useful.

Thoughts?

Bulent Ozhorasan

unread,
Feb 13, 2015, 3:57:49 AM2/13/15
to cesiu...@googlegroups.com
I totally agree with Mark's suggestions.
Actually we have experienced the situation Mark describes.
Since TextureAtlas size is limited, after a certain threshold, we get

DeveloperError: Width must be less than or equal to the maximum texture size (8192). Check maximumTextureSize.

We draw on canvas and assign it as an  image of Billboard.
We need to update Billboard image frequently, after a certain time TextureAtlas bloats we get the error above.

Can you suggest a workaround for this?
Thanks in advance.

Matthew Amato

unread,
Feb 13, 2015, 12:16:26 PM2/13/15
to cesiu...@googlegroups.com
While there is definitely a need to improve management of the billboard texture atlas, showing mouse coordinates is probably better served with a DOM element (plus the below code works for any HTML element).  Here's a complete sandcastle example that shows how to do that.  In my opinion, we should probably update the picking example to the below instead of what we currently have there.

var viewer = new Cesium.Viewer('cesiumContainer');

//Create an element to contain the coordinates label
var element = document.createElement('span');
element.style.position = 'absolute';
element.style['pointer-events'] = 'none';
element.style.font = '24pt sans-serif';
viewer.container.appendChild(element);

//Get the last mouse position every time it moves
var mousePosition = new Cesium.Cartesian2();
viewer.canvas.addEventListener('mousemove', function(e){
    mousePosition.x = e.clientX;
    mousePosition.y = e.clientY;
}, false);

//Don't actually do anything until the next render.
viewer.scene.preRender.addEventListener(function(){
    var ellipsoid = viewer.scene.globe.ellipsoid;
    var cartesian = viewer.camera.pickEllipsoid(mousePosition, ellipsoid);
    if (cartesian) {
        var cartographic = ellipsoid.cartesianToCartographic(cartesian);
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

        element.style.display = 'block';
        element.style.top = mousePosition.y + 'px';
        element.style.left = mousePosition.x + 'px';
        element.textContent = '(' + longitudeString + ', ' + latitudeString + ')';
    } else {
        element.style.display = 'none';
    }
});


--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthew Amato

unread,
Feb 13, 2015, 12:26:58 PM2/13/15
to cesiu...@googlegroups.com
Additionally, I've been playing around with animated billboards, basically anything with a fixed number of frames.  I even have a prototype for parsing and handling animated gifs. Since it's a fixed number of frames, there's no memory leak and it's really efficient:

Here's a silly demo I wrote a few weeks ago: http://mramato.github.io/Demos/AnimatedBillboards/ 

These animations are in sync with simulation time (stop when paused/run backwards/etc) but I also plan on adding the option to have them just run continuously like they would on a web page (as well as making it easy to do stuff like play on hover/click/etc..)  This is all through a new helper class at the Entity API layer.

Eventually I'll turn this into an out-of-the box Cesium feature, but for now you can check out the code (and even use it in your own app) here: https://github.com/AnalyticalGraphicsInc/cesium/blob/animated-billboards/Source/DataSources/BillboardAnimator.js

For use cases that essentially involve creating an infinite amount of billboards, the only real fix is to update the textureAtlas code in Billboard collection to allow for texture replacement or compaction (replacement is probably easier).  This isn't on the near term road map but I would be interested in hearing what the use case is in these situations.  For example, in order to fill a 8192x8192 texture with 64x64 images, you would need to create 16384 different textures.  Does anyone have a use case like this that isn't solved by the above?

Thanks


Mark Erikson

unread,
Feb 13, 2015, 5:40:23 PM2/13/15
to cesiu...@googlegroups.com
For clarification, when I said "coordinates", I was referring to lat/lons.  The billboards are showing the coordinates for route waypoints, and coordinates / altitude / other info for various "tracks" (planes, ground units, etc).

If you've got 250 tracks being displayed and data updates coming in every 15-20 seconds, that can add up pretty quickly even if only a subset of the track entries are actually changing between updates.  The solution I implemented at the time was to create a separate BillboardCollection per route and per track, but the performance discussions I've seen suggest that's going to be slower overall than having a single shared BillboardCollection.

If the texture node placement algorithm could be modified to reuse coordinates based on image ID string and size, that would seem to solve the issue.

Matthew Amato

unread,
Feb 22, 2015, 10:13:18 PM2/22/15
to cesiu...@googlegroups.com
Thanks Mark, that's a good use case and makes perfect sense.

yousef...@gmail.com

unread,
Dec 15, 2015, 10:27:23 AM12/15/15
to cesium-dev
Hi Matthew,

I'm using your BillboardAnimator code to render looping billboard animations. However, the different frames seem to "shake" a little bit. It seems like there are small offsets between one frame and the other.

I don't think it's a bug in your new code, but my suspicion it's the way Cesium renders the image textures (I'm new to this part though). Do you have any suggestion on what could be causing this?

Thanks,

Reply all
Reply to author
Forward
0 new messages