Skip to content
View on GitHubSample viewer app

Configure the environment settings in a local scene to change the lighting conditions and background appearance.

Image of Configure Scene Environment

Use case

The scene environment defines the appearance of a scene. This includes sky and background color settings, whether objects in the scene cast shadows, and the lighting used to illuminate the scene.

For an exploration scenario, like a city planning app, a developer might decide to enable sun lighting and direct shadows so the user can see how buildings and trees cast shadows at a given date and time.

For an analytic scenario, like examining a building scene layer, the developer may choose to use a virtual light source with shadows disabled and a solid background color instead of the atmosphere.

How to use the sample

At start-up, you will see a local scene with a button at the bottom to open the scene environment controls. Adjusting the controls will change the scene's environment, altering the presentation of the scene.

Sky and Background color settings

Toggling the “Stars” and “Atmosphere” buttons will enable or disable those features.

Selecting a color from the dropdown will set a solid color for the background color. Selecting a new background color will disable the stars and atmosphere so you can see the new color.

Some notes about the behavior of the sky and background:

  • The atmosphere is rendered in front of the stars and the stars are rendered in front of the background color.
  • Stars are not rendered when using virtual lighting.
  • To fully see the background color, atmosphere and stars must be deactivated.
  • The background color shows in the night sky if the atmosphere is enabled and the stars are disabled.

Lighting settings

The lighting buttons switch between sun lighting and virtual lighting. Switching to virtual lighting disables the “Stars” button since stars do not exist in a virtually lit scene. The time slider is also disabled under virtual lighting since time does not have an effect on the virtual light.

The “Shadows” button will enable or disable the rendering of shadows for 3d objects in the scene. Shadows are not rendered for surface terrain.

If sun lighting is active, the slider under the buttons will set the hour of the day ranging from midnight to 11pm (23:00). Dragging the bar will change the position of the simulated sun causing changes to shading and direct shadows.

How it works

  1. Create a ArcGISScene from an online resource and add it to the LocalSceneView. The sample’s controls are updated to reflect the web scene's initial environment.
  2. Changes to the sky and background color settings will set values directly on the SceneEnvironment object.
    • isAtmosphereEnabled and areStarsEnabled are boolean properties dictating whether the atmosphere and star field are visible.
    • Colors selected from the dropdown are set to the backgroundColor.
  3. Changes to the settings in the lighting controls manipulate the SceneLighting object in the SceneEnvironment.lighting property.
    • Switching between “Sun” and “Virtual” lighting assigns a new SunLighting or VirtualLighting object to the lighting property.
      • Sun lighting simulates the position of the sun based on a given date and time. This includes lighting conditions for day, twilight, and night.
      • For virtual lighting, the light source is always on and is slightly offset from the camera. As the scene rotated or panned, the light source stays in the same position relative to the camera.
    • The “Shadows” button sets the areDirectShadowsEnabled boolean property on the lightning object. This toggles the shadows cast by objects in the scene.
    • If SunLighting is active, manipulating the slider changes the hour of the simulatedDate property on the lighting object. VirtualLighting does not have a slider because the lighting is always the same regardless of time.

Relevant API

  • ArcGISScene
  • LocalSceneView
  • SceneEnvironment
  • SceneLighting
  • SunLighting
  • VirtualLighting

About the data

The WebM Open 3D Esri Local Scene used for this sample contains a clipped local scene consisting of a surface and 3D objects representing the buildings. The scene is located in Santa Fe, New Mexico, USA.

Tags

3D, environment, lighting, scene

Sample Code

ConfigureSceneEnvironmentViewModel.ktConfigureSceneEnvironmentViewModel.ktMainActivity.ktConfigureSceneEnvironmentScreen.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* Copyright 2026 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.configuresceneenvironment.components

import android.app.Application
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.arcgismaps.Color
import com.arcgismaps.mapping.ArcGISScene
import com.arcgismaps.mapping.PortalItem
import com.arcgismaps.mapping.view.SceneEnvironment
import com.arcgismaps.mapping.view.SunLighting
import com.arcgismaps.mapping.view.VirtualLighting
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import kotlinx.coroutines.launch

/**
 * Holds UI state for the configure scene environment sample and applies user choices to
 * the ArcGIS [SceneEnvironment].
 */
class ConfigureSceneEnvironmentViewModel(app: Application) : AndroidViewModel(app) {

    // The scene displayed by the SceneView composable.
    val arcGISScene: ArcGISScene = ArcGISScene(
        item = PortalItem("https://www.arcgis.com/home/item.html?id=fcebd77958634ac3874bbc0e6b0677a4")
    )

    // The SceneEnvironment of the scene, used to apply changes to the environment based on user input.
    private val _sceneEnvironment: SceneEnvironment
        get() = arcGISScene.environment

    // Message dialog view model for error handling.
    val messageDialogVM = MessageDialogViewModel()

    // UI state variables that mirror the properties of SceneEnvironment.
    // These are used to update the UI when changes are made.

    var isAtmosphereEnabled by mutableStateOf(_sceneEnvironment.isAtmosphereEnabled)
        private set

    var areStarsEnabled by mutableStateOf(_sceneEnvironment.areStarsEnabled)
        private set

    var backgroundColor by mutableStateOf(_sceneEnvironment.backgroundColor)
        private set

    var lightingType by mutableStateOf(
        if (_sceneEnvironment.lighting is SunLighting) LightingType.SUN else LightingType.VIRTUAL
    )
        private set

    var areDirectShadowsEnabled by mutableStateOf(_sceneEnvironment.lighting.areDirectShadowsEnabled)
        private set

    var timeOfDaySeconds by mutableFloatStateOf(43_200f)
        private set

    // Allowed slider bounds for time-of-day.
    val timeOfDaySecondsMin = 0f // 12:00 AM
    val timeOfDaySecondsMax = 82_800f // 11:00 PM

    // Use the Santa Fe time zone so entered times match local scene time.
    // Santa Fe's time zone is America/Denver.
    private val _sceneTimeZone = ZoneId.of("America/Denver")

    // Anchor the selected time to one date so we can convert local clock time to an Instant.
    private val _sceneDate: LocalDate = LocalDate.now(_sceneTimeZone)

    init {
        viewModelScope.launch {
            arcGISScene.load().onFailure { messageDialogVM.showMessageDialog(it) }
        }
    }

    /** Enables or disables atmospheric rendering. */
    fun updateAtmosphereEnabled(enabled: Boolean) {
        isAtmosphereEnabled = enabled
        _sceneEnvironment.isAtmosphereEnabled = enabled
    }

    /** Enables or disables stars. */
    fun updateStarsEnabled(enabled: Boolean) {
        areStarsEnabled = enabled
        _sceneEnvironment.areStarsEnabled = enabled
    }

    /**
     * Sets the scene background color.
     *
     * A solid background color is most visible when atmosphere and stars are disabled.
     */
    fun updateBackgroundColor(color: Color) {
        backgroundColor = color
        _sceneEnvironment.backgroundColor = color
        // Setting a background color should make atmosphere and stars off so the color is visible
        updateAtmosphereEnabled(false)
        updateStarsEnabled(false)
    }

    /** Switches between sun-based lighting and virtual lighting. */
    fun updateLightingType(newType: LightingType) {
        lightingType = newType
        when (newType) {
            LightingType.SUN -> {
                // Rebuild sun lighting with the currently selected scene time.
                val sunLighting = SunLighting(simulatedDate = instantFromSeconds(timeOfDaySeconds), areDirectShadowsEnabled = areDirectShadowsEnabled)
                _sceneEnvironment.lighting = sunLighting
            }

            LightingType.VIRTUAL -> {
                val virtualLighting = VirtualLighting(areDirectShadowsEnabled = areDirectShadowsEnabled)
                _sceneEnvironment.lighting = virtualLighting
            }
        }
    }

    /** Enables or disables direct shadows on the active lighting model. */
    fun updateDirectShadowsEnabled(enabled: Boolean) {
        areDirectShadowsEnabled = enabled
        _sceneEnvironment.lighting.areDirectShadowsEnabled = enabled
    }

    /** Updates scene local time using seconds since midnight. */
    fun updateTimeOfDaySeconds(seconds: Float) {
        timeOfDaySeconds = seconds
        val newInstant = instantFromSeconds(seconds)
        (_sceneEnvironment.lighting as? SunLighting)?.simulatedDate = newInstant
    }

    // Converts seconds since midnight into an Instant used by SunLighting.
    private fun instantFromSeconds(seconds: Float): Instant {
        return _sceneDate
            .atStartOfDay(_sceneTimeZone)
            .plusSeconds(seconds.toLong())
            .toInstant()
    }

}

/** Lighting options shown in the segmented control. */
enum class LightingType(val displayName: String) {
    SUN("Sun"),
    VIRTUAL("Virtual")
}

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