Cesium officially supports terrain rendering!

Hey folks,

I just wanted to let everyone know that we just merged the terrain branch into master, so Cesium now officially supports global terrain rendering! If you use our zipped releases, it will be included in b14, which will be posted in about two weeks.

You can try it out here:


To use terrain in your own applications, check out the new Terrain Tutorial:


Over the next couple of days, I’ll be updating the terrain roadmap to more accurately reflect where we are and where we’re going - it’s a bit of a mess at the moment. If you have any questions or comments, please post them here.



Well done Kevin and team! It’s great to see this now in master.

We're currently examining options for a virtual globe-based application, and Cesium's looking like the best option so far. Is the Cesium terrain server available for standalone use? We would need to host our own terrain server, and most likely build our own terrain dataset as well.


Mark Erikson

Hi Mark,

I’m glad you like what you see in Cesium so far. We’re definitely planning to offer a terrain server for use on private networks, but it may be a bit before we work out the details. If you want, shoot me a (private?) email telling me a bit about your business and maybe we can work something out sooner.

In the meantime, you have three pretty decent options, in approximate order of difficulty. One is to host your terrain using ArcGIS Server. Cesium’s ArcGisImageServerTerrainProvider can be used to access terrain heightmap TIFs hosted in this way. The second is to create tools to process your data into the format used by the CesiumTerrainProvider, which is documented here: https://github.com/AnalyticalGraphicsInc/cesium/wiki/Cesium-Terrain-Server. The final option is to develop a custom TerrainProvider that accesses your terrain in its current format or in a format that is easier for you guys to work with. Let me know if you want more details about any of these options.



I forgot about one last option, and it’s a pretty good one.

I just added support to Cesium for VT MÄK’s VR-TheWorld server. It haven’t used VR-TheWorld myself (other than their public server), but it sounds like exactly what you need. Check it out: http://www.mak.com/products/terrain/streaming-terrain.html


Hello guys,

I am trying to set up and use WebMapServiceTerrainProvider, and ajax requests are returning the .bil images, the provider seems to parse them ok, at least no error messages shown, but terrain layer is not rendered, it is completely absent. Any ideas what could it be?

Thank you in advance,


Hi Alex,

Are there no error messages in the browser’s console, either? Is your WMS server on the internet by any chance? The easiest way to figure out what’s happening would be to take a look myself.


Hi Kevin,

I am going to set up new DEM wms layer in geoserver tonight, and will let know the details.

Thank you much,


Hi Kevin,

I have prepared elevation layer based on geotiff images by meas of geoverver imagemosaic plugin. The elevation model is based on http://en.wikipedia.org/wiki/Australian_Height_Datum . So the height is in meters starting from 0. The WebMapServiceTerrainProvider downloads and parse the images without errors, but rendered elevation on map is incorrect, perhaps _terrainDataStructure should be tweaked but am not quite sure what is heightScale etc.

Resulted terrain at first looks like pyramids then squares divided by cracks (attached). Also attached single time which is received from geoserver.

Can you please, kindly give a clue how it should be configured?

Thank you,


kegs_geo-dem_combab.zip (2.78 KB)

Sorry, for my previous post. The WebMapServiceTerrainProvider works flawlessly, the reason of the gaps is in my elevation data.



WebMapServiceTerrainProvider.js (10.3 KB)


Now I’m trying to understand the terrain provider. Below is a bit of code from my experiments :

    this._tileWidth = 16;

    this._tileHeight = 16;

    // tiling scheme handling

    this._tilingScheme = new Cesium.GeographicTilingScheme({

        // extent : this._extent,  // (1)

        numberOfLevelZeroTilesX : 2,

        numberOfLevelZeroTilesY : 1


    this._levelZeroMaximumGeometricError = Cesium.TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(


        this._tileWidth, // (2)



    this._terrainDataStructure = {

        heightScale : 1.0,

        heightOffset : 0.0,

        elementsPerHeight : 1,

        stride : 1,

        elementMultiplier : 256.0,

        isBigEndian : true


    var width = 16; (2)

    var height = 16;

    var myArray = new Array(width * height); // (3) some heightmap data...

    var heightBuffer = new Uint16Array(myArray, 0, width * height);

    this._terrainData = new Cesium.HeightmapTerrainData({

        buffer : heightBuffer,

        childTileMask : 15,

        width : width,

        height : height,

        structure : this._terrainDataStructure



  1. Uncommenting (1) leads to hanging Cesium widget (I use latest b19 version). I need only extent with terrain data from the “myArray” (3). In version b18 there were no hanging and even the extent was shown somehow, but rendering artefacts appeared (big white quad :slight_smile: ) and no globe rendered.

  2. It seems that only small tiles are possible. Tiles with resolution equal or greater than 256x256 (2) cause out of memory errors. My case is 512x512 tiles.

The only solution I see at this moment is something similar to VRTheWorldTerrainProvider implementation. Walkaround for the described problems seems to be lot of work to do… Any ideas/help appreciated!

Many thanks in advance!


Hi Artem,

Non-global terrain providers aren’t well tested, so I’m not surprised to hear there are issues there. Can you determine where it is hanging? You should be able to wait for it to hang and then break in the debugger.

WebGL (in the absence of an extension) can only use an index buffer of type Uint16. That means the a vertex buffer can have no more than 65536 vertices. That’s 256x256. Any more than that would need to be rendered with multiple draw calls anyway in unextended WebGL. It’s possible we could use the OES_element_index_uint extension to render these big tiles, but we haven’t done that. I think tiles that big would interfere with LOD selection as well, making you render far too many triangles in common scenes. With CesiumTerrainProvider, we started out with 256x256 tiles and eventually reduced that to 65x65 because we saw better results. By the way, power of 2 plus one sizes (like 65x65) are more efficient for upsampling, so I recommend you use them if possible.


Kevin, thank you for the quick responce!
The explanation about WebGL is very usefull. Now I see that it is necessary to split such a big tiles manually.

The error stacktrace is:

“options.primitiveType is required.”








I have difficulty with debugging Cesium because of the only error message during render loop that is shown in the console is:

TypeError: widget.onRenderLoopError is undefined Cesium.js:100599

How to fix it?



It looks like this is a bug in Cesium. The error event is not properly
initialized in the CesiumWidget. I'll fix it in master, but in the
meantime, just comment out the line that's failing:

widget.onRenderLoopError.raiseEvent(widget, e);

and replace it with:


Thank you, Scott!

After adding the property :

primitiveType : PrimitiveType.TRIANGLES

To the options object, passed to the Geometry constructors in the fillPoles method, Cesium began to work like in previous b18 version. But there are still problems - weird texturing, only the extent is rendered and the rest of the globe is transparent. Besides it works slower.

It is easy to reproduce:

var extent = Cesium.Extent.fromDegrees(80,50,85,60);

widget.centralBody.terrainProvider = new Cesium.EllipsoidTerrainProvider({

tilingScheme : new Cesium.GeographicTilingScheme({

extent : extent,

numberOfLevelZeroTilesX : 2,

numberOfLevelZeroTilesY : 2



The solution I see without modifying Cesium sources is alignment of the required extent to the global tile grid, but it doesn’t look good.

If posible I’m ready to contribute to make Cesium supporting terrain extents.



Hi Artem,

Keep in mind, the terrain is the globe. By limiting the extent of the terrain provider, you’re effectively saying that you don’t want to see the globe surface outside of that extent.

If you want to use your own terrain source within an extent, and then use the regular EllipsoidTerrainProvider outside of that extent, you’ll need to write a terrain provider that does that combining itself. It was an early design decision in the Cesium terrain engine to not support automatically combining terrain from multiple sources. We could revisit that decision someday, but probably not anytime soon because combining terrain from multiple sources can usually be done much more efficiently on the server side.


Hi Kevin,

I just had two quick questions regarding terrain in Cesium and the Cesium Terrain Server.

1) It appears as though the data hosted by the Ceisum Terrain Server (http://ceisum.agi.com/smallterrain/) has been properly re-referenced against the WGS 84 ellipsoid (from the WGS 84 geoid: EGM96, for the SRTM source at least). Is this correct? Performing the calculation myself for a few locations shows small discrepancies (5 to 10 meters) between the "smallterrain" values, so I wanted to confirm. I expect the discrepancy comes from the resolution of the EGM96 model used, and possibly the other data sources that are merged with the SRTM data, in the generation of the "smallterrain" dataset.

* http://www.cgiar-csi.org/data/srtm-90m-digital-elevation-database-v4-1#download
* http://earth-info.nga.mil/nga-bin/gandg-bin/intpt.cgi

2) Are there any plans to include/expose the geoidal reference/concept in Cesium to allow for such calculation on the client? And if not, do you think the ability to "ground clamp" primitives to the "terrain" (in addition to depth-culling) is a likely feature? I'm thinking of a scenario where enabling/disabling elevation is a necessary feature.

Thanks for all of the great work!

Hi Nate,

Yes, the smallterrain data has been adjusted to reference the WGS84 ellipsoid, even though the source data (GTOPO30 and SRTM) is referenced to EGM96. 5-10 meters error is a bit higher than I would have guessed, but not totally out of line. The resampling process is probably responsible for a lot of the error. We have to resample the source data to fit the desired grid since we’re using heightmaps.

I’m currently working on a new terrain dataset based on meshes rather than heightmaps, and I expect that will offer better accuracy.

Regarding #2, yes, we’d like to eventually expose EGM96 (or maybe 2008?) on the client. This will be necessary for all the vector and raster data that is referenced to mean sea level. We also do intend to support clamping of primitives to the ground. I can’t say for sure when either of these will happen, though. Contributions welcome, of course!


Of course! Thank you for the reply. I wound up reading through the Terrain and Imagery roadmap (which has answers to #2 with more insight) only after I made my post:


Thanks again!

Just wanted to say that ground clamping for primitives would be fantastic for what I'm doing, and I'm very glad to hear it's on your radar. I'm currently resorting to server-side image rendering to get ground-clamped visualization - it works, but using primitives would look a heck of a lot better.