Models are deforming in 3D tiles

Hello! I am having some odd performance and model issues when I attempt to run my KML/COLLADA through the tiling pipeline by uploading into ION and selecting “3D Tiles.” I have a KML file for Aviation Facilities in the U.S. There are something like 20k facilities. Each “model” then in the KML file is referencing the one .dae file in my zipped (kmz) upload. ION seems to handle tiling it just fine but interestingly when I run it in a sandcastle demo there are some serious performance issues as well as… “model-degradation” let’s call it. Another thing to note is that the performance is only an issue, once the camera drops below a specific height relative to ground within the viewer. I can move the camera to the middle of the ocean (meaning no models should be loaded) and still, the moment I would reach close enough to “ground” the performance would immediately tank.

What am I doing wrong?

This image represents an upload where I ensured there were only 2 data points (airports) and therefore 2 model references of the one model.

This image is 10k airports

This seems to be a duplicate of COLLADA models deformed and performance bad with large number of references

Correct, I wasn’t sure if I had posted in the correct sub-forum to begin with. I thought maybe this is more of a JS or cesium pipeline code issue than specifically an issue with ION.

Yes, I had seen that other thread and considered to move it into the CesiumJS section, but… I also wasn’t entirely sure where it belongs.

Until someone chimes in who has a better idea:

The second screenshot looks like a precision- or quanization issue. I don’t know whether there is any point where quantization comes into play. But precision might come into play: If that input contains these model like “instances”, and their position (on the globe) is given with some huuuge translation value (like a position of (400000, 300000, -450000) or so), then this could explain the effect.

One possible step towards confirming that: When you move the camera in the second screenshot, does the model stay exactly like this, or does the model “wiggle” and “deform” continuously while moving the camera?

(If it “wiggles”, then it’s probably a precision issue, similar to Precisions, Precisions | DME Component Libraries for .NET 2025 r1 - but that wouldn’t immediately help here. It would still be necessary to find out what exactly ion is generating from that input data, and whether there is a way to avoid this effect…)

“When you move the camera in the second screenshot, does the model stay exactly like this , or does the model “wiggle” and “deform” continuously while moving the camera?”

Good question! The model itself actively deforms in a random pattern as the camera moves.

One thing that I failed to mention was that the issue is dependent on the number model references. Below are some screenshots of some notes I took on this.


Again, it’s hard to pinpoint the error just from that description. (I’m also not deeply familiar with COLLADA/KML in particular, or what ion is generating from that). Does that tileset have a reasonable size (and is it not confidential in any way) so that it could be shared, for further investigation?

It’s public FAA data, so sharing it is not a problem.

with_models_half.kmz (2.8 MB)

So… I had a short look at this, and have identified the reason for the behavior, but it’s not immediately obvious how to resolve this.


Analysis

… for curious nerds.

I uploaded that KMZ to ion. Looking at the resulting tileset did not help much, because … nothing is visible. A tl;dr is that setting

viewer.scene.camera.setView({
  destination: new Cesium.Cartesian3(-801073.3215359622, -5488208.485999448, 3138821.543496793),
  orientation: new Cesium.HeadingPitchRoll(5.666925725502479, -0.7806982622768279, 6.283185304491835),
});

will zoom to one of the cars/instances.

And for those who might not know what I’ve been talking about when I mentioned the “wiggling”, here’s a short screencap:

Cesium Forum 43800 wiggle

By default (for tests like this) I enable debugShowBoundingVolume for the tileset. And this one is actually somewhat … interesting:

Yup. That white line there is a bounding region. A single, huuuuge bounding region that essentially covers the entire globe.

The tileset consists of a single tile - namely, one I3DM file that refers to the GLB with that car. As mentioned above: The effect is visually what you’d might expect to be precision errors, as described in Precisions, Precisions | DME Component Libraries for .NET 2025 r1 . The solution is usually to define an “RTC center” (relative to center center (sic)) and store the positions relative to that. For I3DM data, CesiumJS is actually computing such an RTC center. And that usually avoids the jittering. But one can see what the issue is in this case: These are some of the positions that are stored in the I3DM:

They are nowhere near each other. These instances cover the entire globe. So the bounding sphere center is roughly the center of earth, and that whole “relative to center” approach makes no sense any more.


Possible approaches

I don’t know “the” solution for that from the tip of my head. What the tiler is doing there usually makes sense: There are many instances. This should become some I3DM. The fact that the instances cover the whole globe is not anticipated there.

(It’s unlikely that some ~“special handling” can be introduced there. I know, people are pretty quick to come up with solutions for something like this. These solutions are usually quick, elegant, … and wrong. E.g. “Check whether the bounding sphere of the instances is large, and split them into multiple I3DMs” - yeah, define ‘large’ and ‘multiple’…)

One approach could be to do this (“manually”), for this particular data set, with the knowledge that one can have about this particular data set. For example: One could split that KML file into ~50 KML files (each containing 20 instances or so), and hope that the tiler can process this in any way, and that it will create 50 I3DM files that do not expose this “jittering”.

A completely different approach would be to move this instancing to the tileset level. It should be fairly trivial to parse that KML file, and create a tileset.json that just contains tiles that refer to the model, each tile having the proper transform to put it at the right position. Of course, this would mean that it would not benefit from the GPU-based instanced rendering, and cause performance issues for a few thousand model instances.

(Somewhat related: Consider convenience functions to create instanced models · Issue #84 · CesiumGS/3d-tiles-tools · GitHub )

A mix of that could be to put more time and effort into such a functionality. Keep the metadata. Apply some K-Means clustering of the points. Compute the maximum error that is introduced by a certain RTC center, and minimize that. Some “research” could be done here (or some “hacks”, if it’s supposed to be focussed on a quick solution). I’ll leave it at that for now, maybe others want to chime in.

1 Like

A short addendum, maybe from a more “practical” point of view:

When you load this tileset, then you don’t see the cars. You have to zoom to a very specific place to even see one. And one could make a point that it does not even make sense to use an I3DM and “theoretically” render these cars. If these ~10000 instances are somewhat evenly distributed over the globe (or even the landmass, and even when it’s 100000 instances), you’d probably never be able to see more than a few of them (because when looking closely at one, then all others would be smaller than a pixel).

So I think that it should be possible to create a tileset.json from that, assign proper bounding volumes and a sensible geometricError to the tiles, and not run into performance issues.