Some doubts about terrain provider data structure

I’m new to Cesium, so forgive the basic question I’m submitting.

We need to define our own terrain provider to serve highly detailed elevation data.

I’ve read the documentation and the four providers which Cesium provide, but I’m not sure about the effects and the appropriate options to define.

1 - the heightmapwidth: it defines the number of vertices in each tile, right? What is the effect of changing it? I mean, if my tile is 256x256 pixels and I can serve a height value at each pixel, should I set it to 256?

2 - stride/elementsPerHeight: aren’t they dependent? If I have 2 elements per height, doesn’t it follow that the stride is 3?

3 - elementMultiplier: this is quite obscure to me… It multiplies the values of height of each element, just in case stride is > 1. What is the benefit of having this multiplier? Just to manage the cases of values that don’t fit a Uint16?

Thansk for your precious help,


Hi Giovanni,

  1. _heightmapWidth (as seen in CesiumTerrainProvider) controls level-of-detail selection. If the least-detailed level of the tile pyramid, level zero, has a width of 256 vertices, then that tile has less error (relative to the most-detail terrain surface) than a tile that has only 65 vertices. With a heightmap, we don’t know precisely how much error the tile has in either case. But the width is an input to TerrainProvider.getEstimatedLevelZeroGEometricErrorForAHeightmap, which, as the name implies, comes up with an estimate. The value you use here doesn’t strictly have to be the same as your actual heightmap width, but it usually should be.

A couple of notes about heightmap dimensions that aren’t directly related to your question. WebGL currently only supports Uint16 mesh indices, which means that a single mesh can have no more than 65536 vertices. That means you can’t use a 256x256 tile size because that’s already exactly at the limit, and Cesium needs to add a few more vertices in order to avoid cracks between tiles. Also, for best performance, tiles should have “power of two plus one” dimensions. So, if possible, I recommend you use 65x65 or 129x129 tiles.

  1. Typically, stride and elementsPerHeight will have the same value. But that may not be the case if the input buffer has data other than heights in it. For example, if elementsPerHeight is 2 and stride is 4, the first two elements will be interpreted as a height, the next two will be ignored, and the two after that will be the next height.

  2. Yes, it’s needed anytime a height is composed of more than one element. ArcGisImageServerTerrainProvider is an example of this. In that provider, heights are encoded in a PNG. Web browsers provide access to PNG data via Canvas and the getImageData function, which always returns 32-bit RGBA colors. So in the case of our terrain provider, the RGB channels form a 24-bit integer, and the alpha channel is ignored. So we use a stride of 4, an elementsPerHeight of 3, and the elementMultiplier is 256. If elementsPerHeight is 1, as it is in CesiumTerrainProvider, elementMultiplier is ignored.


Thanks very much Kevin for the explanation.

Point 2 and 3 are quite clear.

Point 1 not so much, but it’s ok :slight_smile:

I have to fully understand the LOD selection yet. In 2D WebGIS we don’t have such a concept… the tile selction simply depends on extent and zoom level. Anyway I suppose it’s not so foundamental in this moment.

Yet __heightmapWidth defines the number of vertices in each tile. At a zoom level of, i.e., 18, I have approximately a resolution (for panar projections) of 0.596 m/pixel. If I have 65 vertices it means that I have at most a mesh with 0.596/(65/256) = 2.212 m/pixel -> 2.212 is also the horizontal resolution of my terrain surface. Right?

My DEM has a resolution of 1 m, so with 65 vertices for tile I would loose quality. 129 would be much better.

Is this approach correct? Am I completely on the wrong way?

thanks again,


At level 18 with a geographic projection, there are 524288 tiles. If each tile has 65x65 vertices, and the vertices overlap at their edges, then the there are approximately 33554432 unique samples. The circumference of the Earth at the equator is about 40 million meters, so samples are about 1.2 meters apart. Level 18 in a Web Mercator projection has about twice that distance between samples because there’s only one tile at level zero instead of two.

Certainly if you have 256x256 tiles at level 18, then you’ll lose detail if you downscale that to 65x65. But all you need to do to overcome that is add more levels. Make a level 19 that simply divides your level 18 tiles into four, and then divide each of those again for level 20.


Yes, calculations are correct. My numbers were for Web Mercator.
I will add more levels. I have to get into the 3D world of globes… data management is quite different then 2D geography! :slight_smile:

The next question will be about how to mix my regional heightmap with that provided by Cesium (i.e. GTOPO30, etc.), outside of my region… I will open another thread.

Thanks a lot.