I am using CesiumJS (v1.107.2) in a Next.js application (client-side only, no SSR) with:
ImageryProvider for map tiles
CesiumTerrainProvider for terrain
During camera movements, especially when zooming into a specific city or area, Cesium keeps sending tile requests continuously.
While zooming, it requests tiles for all intermediate zoom levels and areas, and only after the zoom interaction finishes it finally loads the tiles for the area I actually want to focus on.
Because of this behavior, the final zoomed-in view renders very slowly and feels laggy.
What I observe:
Tile requests are triggered at every zoom step
Many of these requests become irrelevant once the camera settles
Network usage spikes and rendering is delayed before the final tiles arrive
My questions are:
Is there a way to limit, debounce, or prioritize tile requests in CesiumJS during camera movements?
Can Cesium be configured to cancel or deprioritize outdated tile requests when the camera changes rapidly?
Are there recommended best practices for optimizing tile loading when using both an ImageryProvider and CesiumTerrainProvider together?
Would approaches like request throttling, camera event handling, or custom loading strategies help improve this behavior?
Any guidance on how to better manage tile loading and improve zoom performance would be greatly appreciated.
As I know, tile request logic is embedded in Cesium JS(QuadtreePrimitive.js).
Parameter you can control is only viewer.scene.globe.maximumScreenSpaceError.
Thanks for the response! I understand that the tile request logic itself is handled internally in QuadtreePrimitive.js and that maximumScreenSpaceError is one of the main tuning parameters.
However, my main concern is not just LOD quality, but how tile requests behave during rapid camera movements. Right now, a lot of requests are fired for intermediate zoom states, and many of them become irrelevant once the camera settles, which causes unnecessary network usage and delays the final render.
I’m trying to understand whether there is any way to:
– throttle or prioritize tile requests while the camera is moving,
– cancel or deprioritize outdated requests,
– or apply any recommended patterns (camera event handling, request scheduling, etc.) to improve perceived performance.
If there are known best practices or internal hooks for managing this behavior, I’d really appreciate any pointers. Thanks again!
Some of the things that you are describing sound like they could be related to the skipLevelOfDetail flag. You can see several flags and settings that are enabled with skipLevelOfDetai=true. But… admittedly, I did not yet extensively try this out, and can not give specific advice about the settings that could best support your use-case.
Thanks for the suggestion! That does sound relevant to what I’m observing.
I’ll try experimenting with skipLevelOfDetail = true and the related settings to see how it affects intermediate tile requests during zoom.
If you happen to recall which flags or combinations are most impactful for reducing unnecessary requests during rapid camera movements, I’d be very interested to hear. Thanks again!
I believe this is not only a Cesium-specific issue, but rather a general challenge in tile-based map / globe applications (e.g. 2D maps, 3D globes, terrain + imagery systems).
During rapid camera movements or zooming, many engines tend to over-request intermediate tiles that quickly become irrelevant once the camera settles.
Beyond Cesium-specific flags like skipLevelOfDetail, are there any well-known best practices or architectural patterns (either in Cesium or in other mapping engines) to:
reduce unnecessary intermediate tile requests
prioritize final camera state over transient states
or generally optimize perceived zoom performance?
Any guidance or references would be greatly appreciated.
prioritize final camera state over transient states
I’m not aware of a flag to prioritize them. But there is preloadFlightDestinations which at least tries to load the final tiles during the flight (but it is true by default, so there may not be much more to tweak).
Beyond that, you may have seen that there are further “optimization options”, like cullRequestsWhileMoving and so. But I haven’t done dedicated experiments with these.
There are blog posts like Skipping Levels of Detail – Cesium , but this does not describe the exact settings, but apparently, only the effects of certain optimization options that became enabled/default back in 2017. The other extreme is what I just stumbled over during a websearch, namely https://www.mdpi.com/2076-3417/15/2/801 - I haven’t read it, but it seems to analyze the effects of some parameters in great detail.
I’ve occasionally been considering how certain “quality evaluations” could be done here. But I think that this will, eventually, always be very use-case specific: Imagine two applications. One is some “virtual sight-seeing” where the user zooms closely to specific places, and then back to the overview of seeing the whole globe. The other application is some flight simulator, where the camera is moving at a constant height, looking at the horizon. The “patterns” of tiles that are loaded in these applications is vastly different. And I think that both the tileset structure and the optimization parameters in the viewer will have to be tweaked for the specific use case. And I think that this is something that should be examined and documented more thoroughly.
Thanks for the explanations and references, they helped clarify the limits of what can be controlled from the application side.
After reviewing this further, I realized that a large part of the perceived performance issue was caused by additional client-side logic on my side rather than Cesium itself. By simplifying the tile loading path and reducing the workload on the JS layer, the overall interaction and zoom performance improved noticeably.
That said, one thing still feels like a missing piece in Cesium: during continuous camera movement (especially zooming), having a built-in debounce–like mechanism and the ability to abort or deprioritize intermediate requestImage calls when zoom levels change rapidly would significantly improve performance for many map-based use cases. Canceling outdated tile requests once the camera settles could make a big difference here.
Thanks again for the insights, this discussion was very helpful.
There are some mechanisms for cancelling “outdated/obsolte” requests. But this is a non-trivial area of the code, so I can only give a somewhat shallow summary: A certain view/camera configuration causes a set of tiles (i.e. one area, with a certain LOD) to be requested. When the camera orientation changes, and the bounding volumes of the requested tiles are no longer in the view frustum, then these requests should be cancelled.
But you can imagine that this mainly affects the cases where the view direction changes. Specifically, it will not necessarily bring a benefit for the case where the user is continuously zooming in to a certain position, causing requests for some LOD 0, 1, and 2 to go out, and where the requests for LODs 0 and 1 become “obsolete” due to the requests for LOD 2.
This is a bit oversimplified. The “skip LOD” optimization may have the effect that it does not actually request LODs 0 and 1. And even if these LODs turn out to be “obsolete”, one could still make a case for loading them, assuming that they can be loaded more quickly than LOD 2, and therefore, could give the user a feeling of a more “progressive” loading (in contrast to a long delay, followed by the full LOD 2 to suddenly pop in).