Fix: Clamped billboards did not render in 2D/CV scene modes#13639
Open
harrythemorris wants to merge 5 commits into
Open
Fix: Clamped billboards did not render in 2D/CV scene modes#13639harrythemorris wants to merge 5 commits into
harrythemorris wants to merge 5 commits into
Conversation
Contributor
|
Thank you for the pull request, @harrythemorris! ✅ We can confirm we have a CLA on file for you. |
harrythemorris
marked this pull request as draft
July 21, 2026 07:08
harrythemorris
force-pushed
the
fix/clamped-billboard-2d
branch
7 times, most recently
from
July 21, 2026 13:19
9bda7bb to
05f0be6
Compare
harrythemorris
force-pushed
the
fix/clamped-billboard-2d
branch
from
July 21, 2026 13:26
05f0be6 to
5b762b7
Compare
harrythemorris
marked this pull request as ready for review
July 21, 2026 13:29
…rd-2d # Conflicts: # CHANGES.md
Add coverage for the two subtlest parts of the fix: that updateHeights un-projects a tile pick result back to the correct cartographic in 2D and Columbus View, and that a clamped billboard reports the projected map position (with height preserved) in Columbus View.
|
👍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Terrain-clamped billboards were invisible in 2D and Columbus View (or, more accurately, drawn in the wrong place and failing depth test). Un-clamped billboards had peculiar rendering issues in 2D.
Broken 2D left, 3D right
And, lastly, the bounding sphere of clamped billboards in 2D/CV mode often covered the majority of the globe.

A few separate issues contributed to the problem
Position / coordinate frame confusion
Initial debugging with spector.js revealed that no draw commands were submitted after the globe pass, which led me to suspect frustum culling as the culprit.
Logging the 'actualPosition` revealed that the position was outside of the expected range
(-2.1250727546554997, 0.8177268971321392, 4500)(-2301506.550232819, -3718076.377732224, 4633834.269943927)(-5232539.533463152, -8453150.669048188, 10574895.589471862)In 2D and columbus, the coordinate is meant to be in the projected-map frame (swizzled so X=height), but what we got was dramatically out of range height values.
There are two positions attached to billboards when clamped:
The clamped position is the position on the terrain that the billboard should clamp to, and it is updated by
scene.updateHeightcallbacks.The actual position, conversely, is meant to reflect the position that the billboard should actually render in the current rendering frame, as it is the vertex loaded onto the GPU and used for frustum culling.
The breakdown comes from the ambiguity of the coordinate frame - it seems like a lot of code was written assuming only ECEF exists in a bunch of places, which is not true and which I've now learnt debugging this issue 😁
Billboard Clamped Position
The space this is intended to be in is not clear as the
updateFunctionconverted it to ECEF, but then acted upon it as if it were in the projected map frame as it incremented the X to apply a vertical offset.computeScreenSpacePositionassumed that the coordinate was in the current mode frame, and did an unproject step to convert back to ECEF if not 3D. This was not the case and the coordinate was already in ECEF, so did not require any transformation at all. This caused the screen position calculated to be very much incorrect too.Fixes:
Tile pick positions in update height callbacks
QuadTreePrimitive.updateHeightsassumed coordinates coming back fromGlobeSurfaceTile.pickwere in ECEF. However they also reflect the current projected map frame. They were always passed intocartesianToCartographicto get a cartographic out, which converted assuming ECEF and gave the wrong cartographic back.Fixes:
cartesianToCartographic.Three point check at smaller distances
When the camera was close to the billboard, it would not render, but draw commands were submitted. This meant it was likely getting discarded in the shader.
In 2D mode, the globe and billboard are (theoretically) coplanar. But in reality,
getGlobeDepthis relatively imprecise when we are in 2D. The error it produced was greater than the built in "depthsilon" of 10 units used in the three point check, which caused the verts to be erroneously discarded.This was confirmed with a debug shader colouring the billboards by this distance.
3D, green in range, yellow within depthsilon
2D, all red = discarded
BillboardCollectionVS.glslhas a max distance check when determining whether to use the three point check or not, which meant that this symptom did not show at moderate to far distances as the check wasn't run.The proposed fix is to skip the three-point check when in 2D mode, as we are expecting all billboards to pass the depth check against the globe. (This may be a faulty assumption!)
Issue number and link
Fixes #5042
Fixes #12531
Fixes #5041 (I believe, sandcastle and forum link are both dead)
Fixes #8307
Testing plan
Unit tests:
BillboardCollectionspec: aCLAMP_TO_GROUNDbillboard reports the projected map position (not the raw ECEF clamped position) in 2D.QuadtreePrimitivespec: the height cache stores a distinct cartographic per entry and is not mutated by callbacks.Manually verified with this sandcastle, which was AI generated.
Video Before and After
Shows the scenes working in 3D, then 2D, then the red wireframe shows the bounding sphere.
Kapture.2026-07-21.at.23.30.59.mp4
Author checklist
CONTRIBUTORS.mdCHANGES.mdwith a short summary of my changeAI acknowledgment
If yes, I used the following Tools(s) and/or Service(s):
Crush was used to generate the sandcastle and unit tests.
If yes, I used the following Model(s):
Claude Opus 4.8