Proposal: Breaking change to units of eyeOffset.z

Question, who’s using billboard.eyeOffset.z for anything?

Modifying this Z value doesn’t change the apparent screen position of a billboard, it only affects the depth-ordering of the billboard with overlapping items. But the value is expressed in meters, and the number of meters needed to influence depth order changes with zoom distance from the camera. For example, when the camera is far away from some billboards, moving a billboard by as much as a whole meter might not have any effect on depth ordering. But zoom in too close, and that same billboard could end up behind the camera.

So what I’m testing now is the idea of moving the Z value by effectively a percentage of the distance between the object and the camera (or possibly the distance between the object and the near plane of the containing view frustum, still working on that). The goal is to be able to supply a somewhat-arbitrary unitless number, similar to a CSS “z-index” type of unitless number, and have that represent a near-guarantee of depth ordering for different billboards placed at exactly the same location.

There would be no guarantee of the handoff between app-supplied depth ordering and real-world depth ordering for billboards that were not in precisely the same location. Yet I still have hope that this could be made to “seem natural” in a way.

Let’s say you have billboards “A” and “B”, and you want “A” to be in front when they overlap at the same location. But the two are separated by 100 meters, and the user has swung the camera around for a close look at “B”, leaving “A” in the background. In this case, B still occludes A even though A has a higher z-order, due to B being quite obviously in front. But as the user slowly zooms away from the pair, they come closer together onscreen, and at some point “A” pops in front as the percentage-based z-ordering gets large enough to overwhelm the physical distance between them. Essentially, that’s the feature being proposed here: The physical distances control depth order when the camera is close, but when the camera is far enough away that it’s hard to distinguish distances between objects, at some point the app-supplied z-ordering will take over instead of the physical ordering. The details of how close the camera is when this handoff happens can be tuned to some extent by changing the z-order values, but it may not be an exact science.

What kind of API would the community want to see supporting this? Here are some options:

(a) A Boolean flag could be provided per billboard to indicate whether eyeOffset.z was meters (the old behavior) or percentages. This is a non-breaking change if the flag defaults to false, but it means yet more per-billboard JavaScript processing, and takes one additional bit in the scarce array of vertex attributes. In general the API has had a lot of feature creep over the years, and I’m quite hesitant to place more per-billboard configuration options in here. Also, it’s unlikely that meter-based offsets would interact well with percentage-based offsets in the same scene.

(b) The same kind of flag could be placed on an entire BillboardCollection, or on the entire DataSource. I don’t like this option much either, mostly because there’s no good way to indicate in CZML whether this should be enabled, and of course eyeOffset.z can be supplied via CZML. Perhaps the flag could be added to the CZML document packet, and affect the setting on the BillboardCollection owned by the DataSource that loaded the CZML document. This seems a bit clunky, but it does preserve backwards-compatibility, by defaulting to false.

© If the new percentage-based behavior works well enough in practice, we could just declare that the old way is not useful anymore, and change the specified units on the Z value of eyeOffset. We would keep the existing direction (negative numbers get closer to the camera) and would probably add a multiplier (so it wouldn’t max out at 1.0, maybe it would go to 100.0 or 1000.0, such that typical “old” values still work similarly to before). This could be a minor change but technically still a breaking change (large values would break or get clamped). The advantage of this option is that no new API settings or options are introduced, and no new per-frame JavaScript processing of new options is needed, so no performance hit here (on the JS side, maybe one extra multiply in the vertex shader, which is very cheap).

So you can tell I’m in favor of breaking it to fix it via ©. Would this cause problems with your existing Cesium apps?

Hi Ed,

We use the billboard.eyeOffset.z to get the billboard “above” lines we have (PolylineGraphics and PathGraphics). The billboard is often a pushpin at the start or end of a line.

The billboards mostly have a label too (LabelGraphics), where we use the same yeOffset.z (Cesium.Cartesian3(0.0, 0.0, -0.5)).

Option © will probably work fine for us, assuming that the LabelGraphics will work the same?

Thanks, Willem

Yes, I should have mentioned, Labels are built on Billboards, so whatever happens to Billboard.eyeOffset will automatically work the same in Label.eyeOffset.

Thanks for sharing that you’re using -0.5 for Z. Can anyone else share eyeOffset.z values that are being used in production apps? This will help me establish a good range of inputs to support.



Interesting idea. If we go this route, I would suggest a breaking change, since the non-breaking changes are not clean over the long-term and I suspect many apps would still just work.

With that said, I expect the way that we will do general z-ordering is for the rendering engine to be aware of different primitive types and be able to explicitly put them in different render passes. I don’t know if it will solve all use cases, but it could solve cases like “draw labels in front of polygons”, “draw labels in front of models”, etc.

It should not be hard to tweak the engine if you want to give this a try.