Show realistic lighting and shadows for the specific date and time of day.

Use case
You can use realistic lighting to evaluate the shadow impact of buildings and utility infrastructure on the surrounding community. This could be useful for civil engineers and urban planners, or for events management assessing the impact of building shadows during an outdoor event.
How to use the sample
Select one of the three available lighting options to display that lighting effect. Adjust the slider to show the lighting effect for a particular time of day. The 3D buildings will display shadows when “Sun light with shadows” is selected.
How it works
- Create an
ArcGISSceneLayerand display it in aSceneView. - Create a
QDateTimeto define the date and time of day. - Set the sun time of the scene view to the specified date and time with
m_sceneView->setSunTime(QDateTime). - Set the
lightingModeof the scene view toNoLight,Light, orLightAndShadowswithm_sceneView->setSunLighting(LightingMode).
Relevant API
- ArcGISSceneLayer
- LightingMode
- Scene
- SceneView
Tags
3D, lighting, realism, realistic, rendering, shadows, sun, time
Sample Code
// [WriteFile Name=RealisticLightingAndShadows, Category=Scenes]// [Legal]// Copyright 2020 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.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "RealisticLightingAndShadows.h"
// ArcGIS Maps SDK headers#include "ArcGISSceneLayer.h"#include "ArcGISTiledElevationSource.h"#include "Camera.h"#include "ElevationSourceListModel.h"#include "LayerListModel.h"#include "MapTypes.h"#include "Scene.h"#include "SceneQuickView.h"#include "SceneViewTypes.h"#include "Surface.h"
// Qt headers#include <QDate>#include <QDateTime>#include <QFuture>#include <QTime>#include <QTimeZone>#include <QUrl>
// STL headers#include <cmath>
using namespace Esri::ArcGISRuntime;
RealisticLightingAndShadows::RealisticLightingAndShadows(QObject* parent /* = nullptr */): QObject(parent), m_scene(new Scene(BasemapStyle::ArcGISTopographic, this)){ // create a new elevation source from Terrain3D REST service ArcGISTiledElevationSource* elevationSource = new ArcGISTiledElevationSource( QUrl("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"), this);
// add the elevation source to the scene to display elevation m_scene->baseSurface()->elevationSources()->append(elevationSource);
// add 3D building shells with a scene layer ArcGISSceneLayer* scenelayer = new ArcGISSceneLayer( QUrl("https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/DevA_BuildingShells/SceneServer/layers/0"), this);
m_scene->operationalLayers()->append(scenelayer);}
RealisticLightingAndShadows::~RealisticLightingAndShadows() = default;
void RealisticLightingAndShadows::init(){ // Register classes for QML qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView"); qmlRegisterType<RealisticLightingAndShadows>("Esri.Samples", 1, 0, "RealisticLightingAndShadowsSample");}
SceneQuickView* RealisticLightingAndShadows::sceneView() const{ return m_sceneView;}
// Set the view (created in QML)void RealisticLightingAndShadows::setSceneView(SceneQuickView* sceneView){ if (!sceneView || sceneView == m_sceneView) return;
m_sceneView = sceneView; m_sceneView->setArcGISScene(m_scene);
// add camera and set scene viewpoint const Camera camera(45.54605153789073, -122.69033380511073, 941.0002111233771, 162.58544227544266, 60.0,0.0); m_sceneView->setViewpointCameraAsync(camera, 0);
// set atmosphere effect to realistic m_sceneView->setAtmosphereEffect(AtmosphereEffect::Realistic);
// set the sun time to the calendar setSunTimeFromValue(8.5);
// add sun lighting m_sceneView->setSunLighting(LightingMode::LightAndShadows);
emit sceneViewChanged();}
void RealisticLightingAndShadows::setSunTimeFromValue(double sunTimeValue){ if (!m_sceneView) return;
// convert a double from 0.0 to 23.99 into hours and minutes double remainder = std::fmod(sunTimeValue, 1); int minute = remainder * 60; int hour = sunTimeValue - remainder;
const QTime selectedTime = QTime(hour, minute);
// set a calendar with a date, time, and timezone const QDateTime sunTime(QDate(2018, 8, 10), selectedTime, QTimeZone(-25200)); // To represent the PST time zone during daylight savings time (-7 hours), we use the number of seconds of offset. // 3600 seconds/hour * -7 hours = -25,200 seconds.
// set the sun time to the calendar m_sceneView->setSunTime(sunTime);
// trigger the time in the settings column to update emit sunTimeChanged(selectedTime.toString("h:mm ap"));}
void RealisticLightingAndShadows::setLightingMode(int lightingModeValue){ if (!m_sceneView) return;
if (lightingModeValue == 0) { m_sceneView->setSunLighting(LightingMode::NoLight); } else if (lightingModeValue == 1) { m_sceneView->setSunLighting(LightingMode::Light); } else { m_sceneView->setSunLighting(LightingMode::LightAndShadows); }}// [WriteFile Name=RealisticLightingAndShadows, Category=Scenes]// [Legal]// Copyright 2020 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.// [Legal]
#ifndef REALISTICLIGHTINGANDSHADOWS_H#define REALISTICLIGHTINGANDSHADOWS_H
// Qt headers#include <QObject>
namespace Esri::ArcGISRuntime{class Scene;class SceneQuickView;}
Q_MOC_INCLUDE("SceneQuickView.h")
class RealisticLightingAndShadows : public QObject{ Q_OBJECT
Q_PROPERTY(Esri::ArcGISRuntime::SceneQuickView* sceneView READ sceneView WRITE setSceneView NOTIFY sceneViewChanged)
public: explicit RealisticLightingAndShadows(QObject* parent = nullptr); ~RealisticLightingAndShadows();
static void init();
Q_INVOKABLE void setSunTimeFromValue(const double sunTimeValue); Q_INVOKABLE void setLightingMode(const int lightingModeValue);
signals: void sceneViewChanged(); void sunTimeChanged(const QString& sunTimeText);
private: Esri::ArcGISRuntime::SceneQuickView* sceneView() const; void setSceneView(Esri::ArcGISRuntime::SceneQuickView* sceneView);
Esri::ArcGISRuntime::Scene* m_scene = nullptr; Esri::ArcGISRuntime::SceneQuickView* m_sceneView = nullptr;};
#endif // REALISTICLIGHTINGANDSHADOWS_H// [WriteFile Name=RealisticLightingAndShadows, Category=Scenes]// [Legal]// Copyright 2020 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.// [Legal]
import QtQuickimport QtQuick.Controlsimport Esri.Samples
Item {
SceneView { id: view anchors.fill: parent
Component.onCompleted: { // Set the focus on SceneView to initially enable keyboard navigation forceActiveFocus(); } }
// Declare the C++ instance which creates the scene etc. and supply the view RealisticLightingAndShadowsSample { id: model sceneView: view onSunTimeChanged: sunTimeText => timeValue.text = "August 10, 2018, " + sunTimeText
} Rectangle { anchors { top: parent.top right: parent.right margins: 5 } width: childrenRect.width height: childrenRect.height color: "#ffffff" opacity: 0.7 Column { id: settingsColumn spacing: 5 padding: 15 Text { id: timeValue anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: 16 // text is set from C++ instance }
ComboBox { id: sunLightingSelection anchors.horizontalCenter: parent.horizontalCenter width: 200 model: [ "No Light", "Light", "Light and Shadows" ] currentIndex: 2 onCurrentIndexChanged: { model.setLightingMode(currentIndex); } } Slider { id: sunTimeSlider anchors.horizontalCenter: parent.horizontalCenter opacity: 0.7 from: 0; to: 23.99 value: 8.5 onValueChanged: { model.setSunTimeFromValue(sunTimeSlider.value); } } } }}// [Legal]// Copyright 2020 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.// [Legal]
// sample headers#include "RealisticLightingAndShadows.h"
// ArcGIS Maps SDK headers#include "ArcGISRuntimeEnvironment.h"
// Qt headers#include <QDir>#include <QGuiApplication>#include <QQmlApplicationEngine>#include <QSurfaceFormat>
// Platform specific headers#ifdef Q_OS_WIN#include <Windows.h>#endif
int main(int argc, char *argv[]){ Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setUseLegacyAuthentication(false);#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) // Linux requires 3.2 OpenGL Context // in order to instance 3D symbols QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); fmt.setVersion(3, 2); QSurfaceFormat::setDefaultFormat(fmt);#endif
QGuiApplication app(argc, argv); app.setApplicationName(QString("RealisticLightingAndShadows"));
// Use of ArcGIS location services, such as basemap styles, geocoding, and routing services, // requires an access token. For more information see // https://links.esri.com/arcgis-runtime-security-auth.
// The following methods grant an access token:
// 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. // To generate a token, a user logs in to the app with an ArcGIS account that is part of an // organization in ArcGIS Online or ArcGIS Enterprise.
// 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token.
const QString accessToken = QString("");
if (accessToken.isEmpty()) { qWarning() << "Use of ArcGIS location services, such as the basemap styles service, requires" << "you to authenticate with an ArcGIS account or set the API Key property."; } else { Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setApiKey(accessToken); }
// Initialize the sample RealisticLightingAndShadows::init();
// Initialize application view QQmlApplicationEngine engine; // Add the import Path engine.addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));
#ifdef ARCGIS_RUNTIME_IMPORT_PATH_2 engine.addImportPath(ARCGIS_RUNTIME_IMPORT_PATH_2);#endif
#ifdef ARCGIS_TOOLKIT_IMPORT_PATH_2 engine.addImportPath(ARCGIS_TOOLKIT_IMPORT_PATH_2);#endif
// Set the source engine.load(QUrl("qrc:/Samples/Scenes/RealisticLightingAndShadows/main.qml"));
return app.exec();}// Copyright 2020 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.
import QtQuick.Controlsimport Esri.Samples
ApplicationWindow { visible: true width: 800 height: 600
RealisticLightingAndShadows { anchors.fill: parent }}