Having the actual data may be helpful if the @cesium-nativeruntime team wants to do additional tests. The data in the given form did not have textures. Here is the same data with a “dummy texture” inserted:
CesiumCulling_DummyTexture.zip (2.7 MB)
However, I did some tests in CesiumJS. And this took me way more time than I’d like to admit. But it seemed to be related enough to ongoing efforts ( CesiumJS ignores bounding volume metadata for implicit tilesets · Issue #13195 · CesiumGS/cesium · GitHub, Bounding volume generalizations by javagl · Pull Request #189 · CesiumGS/3d-tiles-tools · GitHub , Bounding volume validation by javagl · Pull Request #359 · CesiumGS/3d-tiles-validator · GitHub ) so that I can justify that. Based on these investigations, I’m reasonably sure that I found the issue:
The bounding volumes of the tileset are wrong.
The tileset uses multiple external tilesets, where each external tileset uses implicit tiling. That’s unusual, but of course, it should work. (There is certainly a lack of test coverage for this. I should create some test data for that). I spent a few hours trying to figure out what exactly is wrong. I converted the implcit tilesets into explicit ones, and combined them into one large tileset, but of course, each step could hide the original issue (or introduce new errors).
However, eventually, I noticed one thing, when loading only one of the implicit tilesets (namely, Tile_0x0.json):


The bounding volumes in that tileset are “reversed”! One could think that in a “center-and-half-axes” representation, this should not really make a difference, but it does. In fact, I also checked it with the SparseImplicitQuadtree sample. Changing the bounding box from
[ 0.5, 0.5, 0.00625, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.00625 ] to
[ 0.5, 0.5, 0.00625, -0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.00625 ]
(i.e. just negating the x- and y-half-axes) shows the same behavior:

The (dark blue) tiles are disappearing, even though only their “negated counterparts” on the other side went out of view!
I therefore re-computed the bounding volumes of the tilesets. But apparently, my local toolchain for doing this (some mix of JglTF and a private project called J3DTiles) doesn’t do this perfectly either. I tweaked it with some additional, manual fixes, but that was a bit tedious for 16 external tilesets.
So the following is a version of that tileset where most of the bounding volumes are fixed, but not all of them!!!
CesiumCulling_NewBvs_Manual.zip (2.7 MB)
Again: This may appear to work (much better, at least), but some bounding volumes are still wrong, and some tiles may still disappear in certain view configurations! I’ll have to update my local tools to get this right. (And so do you
).
The main point is: The bounding volumes and their half-axes have to match the extent of the tile content, in the right coordinate system. For example, using the bounding volume of the ‘SparseImplicitQuadtree’ above, the bounding volumes of
[ 0.5, 0.5, 0.00625, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.00625 ] and
[ 0.5, 0.5, 0.00625, -0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.00625 ]
do technically describe the same bounding volume (a unit rectangle with a tiny height). But with the wrong axis directions, the second one causes a wrong culling behavior. The computation of the child bounding volumes for the implicit tiles relies on the axis describing the extents along the “positive” axes.
(Aside: I think that some of this is not really obvious, and I’m wondering whether and how that could be made clearer in the specification…)