Cesium 3D Model – Fix Floating and Shifted 3D OSM Buildings After Adding Terrain Effect

3d modelcesiumjavascriptterrain

I had made a 3D view of the osm buildings using cesium. In which i had added a terrain effect using the standard cesium terrain provider as below

var viewer = new Cesium.Viewer('cesiumContainer');
var terrainProvider = new Cesium.CesiumTerrainProvider({
  url : '//assets.agi.com/stk-terrain/world'
});
viewer.terrainProvider = terrainProvider;
var dataSource2 = new Cesium.GeoJsonDataSource();
var promise = dataSource2.load('../../SampleData/Hubli_Buildings.geojson');
promise.then(function(dataSource2) {
    viewer.dataSources.add(dataSource2);
    viewer.zoomTo(dataSource2);


    //Get the array of entities
    var entities2 = dataSource2.entities.values;

    var colorHash = {};
    for (var i = 0; i < entities2.length; i++) {
        //For each entity, create a random color based on the state name.
        //Some states have multiple entities, so we store the color in a
        //hash so that we use the same color for the entire state.
        var entity = entities2[i];
        var name = entity.Elev_in_m;
        var color = colorHash[name];
        if (!color) {
            color = Cesium.Color.BROWN; 
            colorHash[name] = color;
        }

        //Set the polygon material to our random color.
        entity.polygon.material = color;
        //Remove the outlines.
        entity.polygon.outline = false;

        //Extrude the polygon based on the state's population.  Each entity
        //stores the properties for the GeoJSON feature it was created from
        //Since the population is a huge number, we divide by 50.
        entity.polygon.extrudedHeight = entity.properties.Elev_in_m;
        entity.polygon.height = entity.properties.Elev_in_m;
    }
}).otherwise(function(error){
    //Display any errrors encountered while loading.
    window.alert(error);
});

After adding the terrain, my geojson 3D seems to be floated and shifted as below

enter image description here

I would like to know how to avoid this shifting effect after adding the terrain.

Best Answer

Polygons don't automatically pick up terrain height values when you enable Cesium terrain. You need to set entity.polygon.height for each polygon, and also add that same height to your existing entity.polygon.extrudedHeight. In other words, extrudedHeight is the absolute height (above WGS84) of the top of the extrusion, so if you have a building of fixed height, you must raise both height and extrudedHeight in unison to lift the building up onto the new terrain.

The Cesium Terrain Demo includes a code sample showing how to read the height values at multiple points on terrain. Click the Sample Everest Terrain button to see this in action.

EDIT: I copied the sampleTerrain code into the question's code above, and the buildings now sit on the terrain. Here's the completed example:

// Selecting the terrain this way allows the base layer picker to show the selection.
var terrain = Cesium.createDefaultTerrainProviderViewModels();

var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProviderViewModels: terrain,
    selectedTerrainProviderViewModel: terrain[1]
});

// This array will hold our cartographic height queries, one per building, and will
// also be populated with the answers.
var terrainSamplePositions = [];

var dataSource2 = new Cesium.GeoJsonDataSource();
var promise = dataSource2.load('../../SampleData/Hubli_Buildings.geojson');
promise.then(function(dataSource2) {
    viewer.dataSources.add(dataSource2);
    viewer.zoomTo(dataSource2);


    //Get the array of entities
    var entities2 = dataSource2.entities.values;

    var colorHash = {};
    for (var i = 0; i < entities2.length; i++) {
        //For each entity, create a random color based on the state name.
        //Some states have multiple entities, so we store the color in a
        //hash so that we use the same color for the entire state.
        var entity = entities2[i];
        var name = entity.Elev_in_m;
        var color = colorHash[name];
        if (!color) {
            color = Cesium.Color.BROWN; 
            colorHash[name] = color;
        }

        //Set the polygon material to our random color.
        entity.polygon.material = color;
        //Remove the outlines.
        entity.polygon.outline = false;

        // TODO: More sanity checking for undefined values etc.
        var position = entity.polygon.hierarchy.getValue().positions[0];
        terrainSamplePositions.push(Cesium.Cartographic.fromCartesian(position));

        //Extrude the polygon based on the state's population.  Each entity
        //stores the properties for the GeoJSON feature it was created from
        //Since the population is a huge number, we divide by 50.
        entity.polygon.extrudedHeight = entity.properties.Elev_in_m;
        entity.polygon.height = 0;
    }

    // Asking for terrain heights is asynchronous, because the answer may
    // reside on the terrain server.
    Cesium.when(Cesium.sampleTerrain(viewer.terrainProvider, 11, terrainSamplePositions), function() {
        // Update all building heights to sit on top of the terrain.
        for (var i = 0; i < entities2.length; i++) {
            var entity = entities2[i];
            var terrainHeight = terrainSamplePositions[i].height;
            // The bottom of the building sits on the terrain.
            entity.polygon.height = terrainHeight;
            // The top of the building adds the building height to the terrain height.
            entity.polygon.extrudedHeight = entity.properties.Elev_in_m + terrainHeight;
        }
    });

}).otherwise(function(error){
    //Display any errrors encountered while loading.
    console.error(error);
});
Related Question