Summary
When a PolylineCollection holds enough polylines that its vertex count reaches 65536, PolylineBucket.updateIndices writes index 65535 into the Uint16Array index buffer. In WebGL 2, PRIMITIVE_RESTART_FIXED_INDEX is always enabled (see here). Because Cesium uses unsigned shorts by default, this means 65535 is reserved and can’t be used as a vertex index. This results in a vertex that spikes to random screen positions every frame.
I’ve hit this a couple times over the last couple of years (see my only other post lol), so I finally went digging for the root cause. I’m fairly sure it’s also what people are seeing in this 2D thread, along with a couple others.
Sandcastle (because I am a model forum user !)
I tried to comment the code enough to make it clear what’s going on. The toolbar lets you see various config options I was going through while testing. You can pick counts that put the vertex buffer boundary either exactly on a polyline boundary (65 points per line) or mid-polyline (73 points per line). Behavior also changes based on shared vs. isolated material.
There’s also a USE_WEBGL1 flag I threw at the top so you can confirm what I said in the summary.
Things came across
With per-frame position updates off, nothing ever glitches
The spike only appears when that polyline shares a draw command with the polylines before it. Giving it its own material makes the spike disappear
Locally changing the split condition in updateIndices so the highest index emitted is below 65535 also eliminates the glitch in every configuration I tried
Code/nitty-gritty
In PolylineBucket.prototype.updateIndices, the check before each segment is
if (indicesCount + 4 > CesiumMath.SIXTY_FOUR_KILOBYTES) {
With indicesCount = 65532, 65536 > 65536 is false, so the segment 65532, 65534, 65533, 65533, 65534, 65535 is pushed and the split only happens on the next segment. That segment contains the reserved index.
EDIT: I explained this poorly, here’s some ms paint:
Why the reserved index makes a massive spike (rather than a dropped triangle), and only while the buffer is being updated, and only when the polyline is batched into a larger draw command? I have literally no idea! I hope never to know.
Possible fixes
I can think of two fixes, either adjusting the splitting (changing both indicesCount + 4 checks to use >=, fixing the between-polyline branch, maybe something else?) or switching to 32-bit indices on WebGL 2. It feels like switching to 32 bit would get rid of this whole class of bug (and gets rid of vertexBufferOffset, _locatorBuckets, whatever the 2d path is doing, etc.), but it would more involved to implement. Plus, you’d need to keep the splitting path around for WebGL 1 contexts and that obviously sucks.
Either way I’d love to throw together a pull request if this isn’t something you already know about.
