Skip to content
View on GitHubSample viewer app

Vertically exaggerate terrain in a scene.

Image of Apply terrain exaggeration

Use case

Vertical exaggeration is useful when the horizontal extent of a landscape is much larger than the vertical relief. Exaggerating elevation makes small terrain variations more visible, which is helpful for visualizations, presentations, and exploratory analysis.

How to use the sample

Open the sample to display a SceneView centered on a location with elevation data. Use the "+" and "-" buttons in the bottom sheet to increase or decrease the terrain vertical exaggeration. The UI shows the current exaggeration factor (1x to 10x).

How it works

  1. Create an ArcGISTiledElevationSource that points to a terrain ImageServer.
    1. An elevation source defines the terrain based on a digital elevation model (DEM) or digital terrain model (DTM).
  2. Add the elevation source to a Surface and assign that surface to a Scene's baseSurface.
  3. Configure the surface's elevationExaggeration using a multiplier factor.

Relevant API

  • baseSurface
  • elevationExaggeration
  • Scene
  • Surface

Tags

3D, DEM, elevation, exaggeration, scene, surface, terrain

Sample Code

ApplyTerrainExaggerationViewModel.ktApplyTerrainExaggerationViewModel.ktMainActivity.ktApplyTerrainExaggerationScreen.kt
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* Copyright 2025 Esri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.esri.arcgismaps.sample.applyterrainexaggeration.components

import android.app.Application
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.mapping.ArcGISScene
import com.arcgismaps.mapping.ArcGISTiledElevationSource
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Surface
import com.arcgismaps.mapping.Viewpoint
import com.arcgismaps.mapping.view.Camera
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
import kotlinx.coroutines.launch

/**
 * ViewModel that prepares a Scene with an elevation source and exposes
 * an elevation exaggeration value that the UI can update.
 */
class ApplyTerrainExaggerationViewModel(app: Application) : AndroidViewModel(app) {

    // Elevation source used by the scene's base surface.
    private val elevationSource: ArcGISTiledElevationSource = ArcGISTiledElevationSource(
        uri = "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"
    )

    // Expose the elevation exaggeration as a mutable state.
    var currentElevationExaggeration by mutableFloatStateOf(1f)

    // Set the camera location to center on Levering, WA.
    private val camera = Camera(
        lookAtPoint = Point(
            x = -119.9489,
            y = 46.75792,
            spatialReference = SpatialReference.wgs84()
        ),
        distance = 15000.0,
        heading = 40.0,
        pitch = 60.0,
        roll = 0.0
    )

    // Create a scene with a topographic basemap and a surface that holds the elevation source.
    val arcGISScene: ArcGISScene = ArcGISScene(BasemapStyle.ArcGISTopographic).apply {
        baseSurface = Surface().apply {
            elevationSources.add(elevationSource)
            // Initial exaggeration value.
            elevationExaggeration = currentElevationExaggeration
        }
        // Set the initial viewpoint using the camera.
        initialViewpoint = Viewpoint(camera = camera, boundingGeometry = camera.location)
    }

    // Dialog helper for showing errors.
    val messageDialogVM = MessageDialogViewModel()

    init {
        // Load the scene.
        viewModelScope.launch {
            arcGISScene.load().onFailure { messageDialogVM.showMessageDialog(it) }
        }
    }

    /**
     * Update exaggeration using an increment or decrement amount.
     * Value is expected between 1 and 10, clamped for the sample.
     */
    fun updateElevationExaggeration(amount: Float) {
        // Update current elevation state with the exaggeration amount
        currentElevationExaggeration = (currentElevationExaggeration + amount).coerceIn(1f, 10f)
        // Update the base surface to honor the current elevation state
        arcGISScene.baseSurface.elevationExaggeration = currentElevationExaggeration
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.