Cesium: Billboard sizeInMeters clamped to 65 kibi-meters

Created on 21 Jul 2020  路  4Comments  路  Source: CesiumGS/cesium

Sandcastle example -- the purple border should line up with the edges of the teal fill, and it does for the smaller shape (44km) but not the larger one (88km).

Per discussion on the forum it looks like at some point the billboard width is being clamped to 65535. I'm guessing height has the same problem. The clamping should be applied to the actual pixel count of the texture, not the logical size.

category - billboards

Most helpful comment

It has to do with GPU memory, not texture size. Every billboard allocates these attributes in the vertex shader: https://github.com/CesiumGS/cesium/blob/master/Source/Shaders/BillboardCollectionVS.glsl#L4
To conserve memory, the width/height are packed as a 16-bit value. Compressing these and other values lets us use one vec4 attribute to represent 6 or 7 different values instead of having 6 or 7 separate attributes.

That being said, I did take a closer look and we do have some free bits in one of the compressed attributes we could use to allow for larger width/height values. Or we could decide add another attribute so we don't compress width/height. We'll just have to keep performance in mind since in the most common use case (when `sizeInMeters = false) width/height are pixel size and will be much smaller than 65535.

All 4 comments

Yes, as pointed out in the forum discussion, this is due to the way we're compressing billboard attributes to send to the vertex shader for rendering. Height will have the same limitations.

https://github.com/CesiumGS/cesium/blob/master/Source/Scene/BillboardCollection.js#L1246

Because a scene can potentially have a very large number of billboards, we have to be very careful about the amount of memory used in order to optimize performance. We might want to throw a DeveloperError in the meantime if the values are larger than expected since this seems like a not-very-common use case.

I don't think I understand. The memory usage should be based on input texture size in pixels, and shouldn't depend on the ("output") rendered texture size in world coordinates, right? Or, you're saying that to conserve memory, the world-coordinate size is being passed as 16-bit packed values? And no other existing use cases exceed 16-bit world-coordinate sizes so it's not a priority?

As for how to handle it, I assume that other shapes are broken up into smaller primitives -- could the billboard texture be applied to a larger number of sub-64k rectangles?

It has to do with GPU memory, not texture size. Every billboard allocates these attributes in the vertex shader: https://github.com/CesiumGS/cesium/blob/master/Source/Shaders/BillboardCollectionVS.glsl#L4
To conserve memory, the width/height are packed as a 16-bit value. Compressing these and other values lets us use one vec4 attribute to represent 6 or 7 different values instead of having 6 or 7 separate attributes.

That being said, I did take a closer look and we do have some free bits in one of the compressed attributes we could use to allow for larger width/height values. Or we could decide add another attribute so we don't compress width/height. We'll just have to keep performance in mind since in the most common use case (when `sizeInMeters = false) width/height are pixel size and will be much smaller than 65535.

So if I understood this correctly, then the point of this compression is that instead of storing the sizes of 1024 billboards as 4 byte + 4 byte (taking 8KB), the sizes are stored as 2 byte + 2 byte (taking 4KB, plus advantages for passing the data to the shader).

As for how to handle it, I assume that other shapes are broken up into smaller primitives -- could the billboard texture be applied to a larger number of sub-64k rectangles?

I'm not familiar with the specific API, but from quickly skimming over it: A workaround might be to split a 100000x50000 billboard into two parts (each being smaller than 65k then), and using Billboard.html#setImageSubRegion to let them show the relevant part of the image. For really large Billboards (where you'd have to split it into, say 6x4 sub-Billboards), this might be a bit clumsy, but could probably be easily wrapped into a function that takes an image and a size and generates the required sub-Billboards, maybe directly as a Billboard collection.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

OmarShehata picture OmarShehata  路  4Comments

pjcozzi picture pjcozzi  路  4Comments

hanbollar picture hanbollar  路  4Comments

lilleyse picture lilleyse  路  4Comments

OmarShehata picture OmarShehata  路  4Comments