I3dm tiles disappearing on camera move

Hello!
I generated i3dm tileset (links to gltfs inside cmpt files) with road signs. Here is the tileset.json.

{
  "root": {
    "geometricError": 0.1,
    "refine": "ADD",
    "boundingVolume": {
      "region": [
        0.64246,
        0.96286,
        0.66265,
        0.97786,
        0,
        300
      ]
    },
    "content": {
      "uri": "http://localhost:8085/content/{level}_{x}_{y}.cmpt"
    },
    "implicitTiling": {
      "availableLevels": 8,
      "subdivisionScheme": "QUADTREE",
      "subtreeLevels": 4,
      "subtrees": {
        "uri": "http://localhost:8085/subtrees/{level}_{x}_{y}.subtree"
      }
    }
  },
  "asset": {
    "generator": "i3dm.export 1.0.0.0",
    "version": "1.1"
  }
}

After adding it to cesium (sandcastle, v 1.111) i have unexpected behavior (gif). On camera move features disappearing and appearing.
3D Tiles Inspector

What can cause this behavior? GeometricError was changed from 0.01 to 100 with no effect. Road signs are close to ground, but not under it.

How to make it visible in all camera positions?

Video

can you try with i3dm.export 2.7.1 ?

@bertt This sounds similar to

Do you have any insights that are related to this thread (and maybe the linked ones) that might explain the observations?

The question here is, very roughly, whether this is an issue in CesiumJS (that should be tracked in Issues · CesiumGS/cesium · GitHub , or whether this might be caused by the underlying data. (And if it’s the latter, I’d be curious what might have caused the issue. For example, whether this is caused by something that could be checked by the validator…)

yeah sure.

One issue was with I3dm’s when setting RTC_CENTER, and having the instance positions relative to this RTC_CENTER. The tiles were drawn OK on loading, but after camera movement and/or zoomin the closest tiles did disappear :frowning:
I’ve not figured out why this happens (it also depended on the model used), I can make a sample with trees if you need it.
As a workaround/fix I’ve removed the RTC_CENTER and just use the ECEF positions in the I3dm’s. It seems to work ok so far.

Now with the 1.1 GPU instancing method I’ve got something similar: trees get shaky when using the ECEF positions (see https://bertt.github.io/cesium_issues/shaky_gpu_instances/issue/).

skaky

Probably because the instance positions are large and the GPU cannot handle it well. But I don’t understand why it works allright when I use the ECEF positions in I3dm…
As a workaround/fix I could probably do an extra node in the GLB with a translation and use relative positions again…

But in general I think it would be easier/less prone to error if we can just use in ECEF positions (instead of something like RTC_CENTER or doing some extra translations) and let CesiumJS figure out the rendering of it. It shouldn’t be too difficult.

One issue was with I3dm’s when setting RTC_CENTER, and having the instance positions relative to this RTC_CENTER. The tiles were drawn OK on loading, but after camera movement and/or zoomin the closest tiles did disappear :frowning:

That sounds like it could be an issue worth tracking. At least, from quickly glancing over the specification of RTC_CENTER in I3DM, it looks like this should be taken into account. If you have example data (preferably, “the same” data, once with the issue and once without it), that could be part of an issue summary.

Now with the 1.1 GPU instancing method I’ve got something similar: trees get shaky when using the ECEF positions

If I understood this correctly, then this happens when putting the actual ECEF tree positions into the TRANSLATION attribute of the EXT_mesh_gpu_instancing.And … in this case, the “jittering” might have to be expected. As you said: The values are simply too large to be represented with 32bit float. And although the translations are not explicitly added to the actual vertex positions, and seem to be conceptually similar to an RTC_CENTER offset: The instancing happens on the level of the GPU itself, with special GL calls, and I assume that’s where the precision is lost.

But I don’t understand why it works allright when I use the ECEF positions in I3dm…

There is some special handling for this.

(The comment there suggests that this may depend on the presence of the RTC_CENTER. This might actually be related to the issue mentioned above: Maybe some of this special handling is not taken into account for some bounding volume/visibility computations or so…, but that would have to be investigated further)

But in general I think it would be easier/less prone to error if we can just use in ECEF positions (instead of something like RTC_CENTER or doing some extra translations) and let CesiumJS figure out the rendering of it. It shouldn’t be too difficult.

If that “It shouldn’t be too difficult” referred to the experience of the developer who uses CesiumJS, then I fully agree :slight_smile: If it referred to the question of how this (simple, easy to use) behavior could be offered by CesiumJS, then it might be a bit more tricky. But probably not unsolvable. One could probably tackle this with an approach that is similar to the “special handling” that I linked to above:

  • Assume that the TRANSLATION of the EXT_Mesh_gpu_instancing might contain large ECEF values
  • compute the average of these translations
  • subtract this ‘average’ from the translations, to obtain the relative translations
  • send these relative translations to the GL call that does the instancing
  • but… add the ‘average’ as a translation to the model matrix for this call

This would boil down to be an “automatic”, client-side (internal) solution for what you proposed as the workaround:

As a workaround/fix I could probably do an extra node in the GLB with a translation and use relative positions again…

That could solve it. With some degrees of freedom of whether this translation should then be in a node of the glTF, or in a tile transform matrix. I think that the latter might be more flexible, because the GLB could then be “centered at the origin”, which might be easier to digest for other viewers. For example: BabylonJS also tends to choke on glTF assets with large node.translation values, and … you might observe some jittering there. This came up recently in A question about cesium render 3dtiles? - #2 by Marco13

ok thanks I will prepare some samples:

  • 2 I3dm’s with tree model (2 instances) and RTC center → one tree is disappearing on camera move

  • 2 I3dm’s with simple box model (2 instances) and RTC center → no issue, works alright

  • 2 I3dm’s with tree model (2 instances) without RTC center → no issue, works alright

Does this mean that it behaves differently depending on whether the inner model is a ‘tree’ or a ‘box’? I’m really curious to see that. In the best case :crossed_fingers: this might already be a valuable hint - insofar that the difference between these models (on the level of the glTF) might lead to the reason for the issue.

Ok two samples, 2 instances with RTC_CENTER in i3dm with attribute ‘oas’ (PW-000168 and PW-000028). Positions on the map are OK, tilesets are
valid according to validator.

1] Tree: https://bertt.github.io/cesium_issues/i3dm_disappearing/tree/

Eastern tree disappears on map navigation

tree_disappears

2] Box: https://bertt.github.io/cesium_issues/i3dm_disappearing/box/

Eastern box does not disappear on map navigation

box_does_not_disappear

I guess this ‘special handling’ with relative to the center fails when having global instances? For example one instance in Japan and one in USA.

I guess this ‘special handling’ with relative to the center fails when having global instances? For example one instance in Japan and one in USA.

It certainly does, and so does any other approach that tries to squeeze antipodes into the same 32 bit numbers. It’s a somewhat artificial corner-case, though: For the things that I3DM is intended for (street lamps, hydrants, trees…), the instances will generally be somehow “local”. For Japan and USA, there would be two I3DMs.
(And … as I mentioned above: I think that it is generally more flexible to do the placement on the earth using the tile.transform instead of baking this into the translation of I3DM or EXT_mesh_gpu_instancing, but of course, both approaches should just work, preferably)

Ok two samples, 2 instances with RTC_CENTER in i3dm

Thanks for that. I’ll try to allocate some time to have a closer look at this. (I might not be able to really dig into the details in the next few days, because there currently are some other higher-priority tasks, but I’ll try to do a quick test and maybe a first analysis soon).
For now, I did a quick search in the CesiumJS issues, and Disappearance of scaled non-uniform i3dm feature · Issue #11617 · CesiumGS/cesium · GitHub and i3dm renders incorrectly when model has non-identity matrix · Issue #11176 · CesiumGS/cesium · GitHub seem to describe some of the behaviors that you also observed here.
(The “disappearing objects” and “jittering” have to be examined independently. In doubt, I’d at least update this issue with the details from this thread and the data sets. Having two data sets that should behave the same, but do not behave the same might make the analysis easier…)

In fact, the two sample locations (with the box and the tree) come from a dataset covering United States, Pacific, the Caribbean, Canada, and Mexico… so not ‘artificial corner-case’ I would say.

FYI I’ve fixed the jittering for now using node transform matrix (and relative instance positions to that) https://bertt.github.io/cesium_issues/shaky_gpu_instances/fix/

Now, there always are numerical limits, and the places and configurations where they show up may be subtle. The fact that one cannot use a single asset with EXT_mesh_gpu_instancing to store precise locations around the globe is one of them. Maybe (!) something like KHR_accessor_float64 Draft Proposal by lexaknyazev · Pull Request #2397 · KhronosGroup/glTF · GitHub will come to the rescue, longer term. But given that the implementations usually rely on glDraw*Instanced calls means that the client (CesiumJS) does not have much influence here.

At the very least, one could consider to point this out more prominently. But … I’m not sure where this should happen. It probably doesn’t fit into the EXT_mesh_gpu_instancing extension specification text. A statement like “when values are too large, they may become imprecise” wouldn’t help much. It could be part of some sort of “best practices guide”. (And far more generally, I think that there should be far more guidance about “How to create ‘good’ tilesets” - there are just too many degrees of freedom…)

I’ll keep this thread on my TODO list, and post any updates or insights here.

Did some more experiments with a global dataset, in this case multiple instanced glb’s are created in a quadtree (so for example 1 glb is for the instances in Oceanie). Now there is no issue with jittering when using relative positions (relative to some kind of center point within the glb).