Potential 3D Model Caching and performance improvements strategy

Hi Cesium’ers,

Good morning/afternoon.

I believe the core team is now closing up for the 1.0 release. Best of luck and thank you so much for such an amazing product.

We’re using Cesium to render large-scale scenarios, and right now we’ve been using billboards to represent our entities as they’re the best-balanced performance/visuals compromise. We’d like to switch to using 3D models (at least for closer visualizations), but the current Cesium implementation is prone to considerable performance and resource usage constraints. We’d like to propose, and publicly contribute, to an improvement in such regards, and to do so ideally in line with the going forward strategy in Cesium’s own roadmap. As such, our main concern is in proposing changes that can be discussed, adopted and maintained by the overall group, as they touch the innards of Cesium’s model rendering.

We’d like to propose on possible improvement on the 3D Models resource management and rendering code. The remainder of this text is mainly written by Sergio Flores, here in copy and also on the list, which has been taking a look into the Model Rendering classes. Here it goes:

Right now the Model class holds both geometry buffers and model transforms, all in one place. This prevents reusing of geometry when we want to have multiple instances of same model, especially bad when the application needs to display the same model hundreds of times in different positions.

In our opinion this class should be split into three classes, Model, ModelCache and ModelTransform. The names themselves are less relevant than the roles they imply.

-Model stores the geometry buffers and other things specific to that model.

- ModelCache would keep copies of all required models, associated by a filename or something else.

- ModelTransform (or ModelInstance or something else) would associate a model with a matrix transformation (and possibly other properties, like letting override the model base texture, diffuse color, etc).

Now to render something in the Globe, the programmer would have to create a ModelTransform instead that receives a Model in the constructor.

The programmer could obtain a model in two ways:

1 - Create the model directly as before (but without transforms)

2 - Ask the ModelCache for the model (the cache will return the Model if already in memory, otherwise will create a new Model and load it from a specified source)

Model’s lifecycle

While just having a ModelCache with a put() and get() methods would be enough for many people, complex applications might require more control, so they might need to be able to unload things as necessary.

As Javascript does not have any kind of automatic reference counting that could be used to unload the WebGL resources when necessary, we could always put the unloading in the hands of the programmer, just adding delete(name) and clear() (to remove everything from the cache).

We can see cases where this could go wrong, like unloading a Model manually that belongs to the cache, and they later call ModelCache.Get() for that same model, and now you get an invalid model.

When I (Sergio) implemented my own graphics engine some years ago, all my resources classes (models, textures, shaders, etc) had the ability to be in two states, loaded or unloaded, and they could be unloaded any time, automatically by the engine or manually by the programmer.

Unloading only destroyed the OpenGL resources, and any time they were necessary again they would be automatically recreated, and this would be transparent to the programmer.

Not only that, but taking advantage of this system, resources were always lazily loaded. If a programmer created an instance of such a model, the model and all textures that belonged to it were only loaded (asynchronously or not) in the exact moment the model appears on the screen.

Cesium does not seem to have any kind of unified resource system (correct me if I’m wrong), and thats a pity, since that way we could easily cache any kind of thing (not only models) and add support for those smart loading/unloading schemes, that could greatly improve performance of more complex applications.

Is this strategy something that we could tweak/work in line with Cesium’s broader purposes?


Hugo Pinto

Sergio Flores

Hi Hugo and Sergio,

Thanks for the interest. We welcome contributions in this area as they are inline with the roadmap (#927): “Reuse texture and vertex buffers when loading multiple models. Probably separate model and instances.”

I believe this can be done without changing the public Model class. Instead, under the hood, we would separate out the node-hierarchy/animations/skins/material-properties and so on from the geometry/texture/materials and implicitly cache the later.

First, what are you trying to achieve?

  1. Lower memory usage and faster loading? I’m confident we can do this without significant work (perhaps 2-5 weeks).

  2. Significantly faster performance? This can be achieved by doing (1) and then (a) using the WebGL instancing extension, and (b) optimizing the command-based renderer in Cesium. (a) will only work on some WebGL implementation. (b) will touch all parts of Cesium and will be a big change.

Let me know your goals and I can provide more concrete guidance.

Also, keep in mind that many optimizations can be done server-side. For example, many models can be combined into a single mesh/node and then rendered client-side in a single draw call. AGI is working on a licensed tool that does this (we used it for NORAD Tracks Santa). I can connect you with AGI if you want or you could write a pipeline with similar optimizations.