In this example, we will learn about 3-D visualisation in R using the package rayshader. The code used in this tutorial was modified from https://www.rayshader.com/. First, we will create a digital elevation model (DEM) with a 1-m spatial resolution. Further, we will add an aerial image at a 20-cm spatial resolution above the DEM. Finally, we will make an animation with 3-D visualisation. The study area is a Rummu quarry (59.227398, 24.193968) - a man-made heap that originated due to the mining of Vasalemma limestone and marble. This place is very popular during the hot season since it is possible to swim and dive in transparent water (link).

Lat’s start with packages installation. We have to install packages from GitHub (not from CRAN! ), otherwise, you will face the problem with plotting. Package remotes is designed to enable downloading the packages from GitHub repositories.

install.packages("remotes")
library(remotes)
remotes::install_github("tylermorganwall/rayshader") 
remotes::install_github("dmurdoch/rgl")

install.packages("magick") # package implements functionality for manipulating 
                            # high-dimensional arrays using efficient vectorised methods

Call the packages we will use:

library(magick)
library(rayshader)
library(raster)
library(rayrender)

Download the DEM data from Landboard Estonia. link

Select 1-m resolution GeoTIFF data for map sheet number 63613. After the file is downloaded - place it to your working directory.

Set your working directory. This should be the folder where you can save the outputs.

setwd("/YOUR/WORKING/DIRECTORY")

Import downloaded raster:

DEM  <-  raster::raster( "63613_dem_1m.tif")   # It works if file "63613_dem_1m.tif" is located in your working directory
crs(DEM) # see the coordinate system
## Coordinate Reference System:
## Deprecated Proj.4 representation:
##  +proj=lcc +lat_0=57.5175539305556 +lon_0=24 +lat_1=59.3333333333333
## +lat_2=58 +x_0=500000 +y_0=6375000 +ellps=GRS80 +units=m +no_defs 
## WKT2 2019 representation:
## PROJCRS["Estonian Coordinate System of 1997 (with axis order normalized for visualization)",
##     BASEGEOGCRS["EST97",
##         DATUM["Estonia 1997",
##             ELLIPSOID["GRS 1980",6378137,298.257222101,
##                 LENGTHUNIT["metre",1]]],
##         PRIMEM["Greenwich",0,
##             ANGLEUNIT["degree",0.0174532925199433]],
##         ID["EPSG",4180]],
##     CONVERSION["Estonian National Grid",
##         METHOD["Lambert Conic Conformal (2SP)",
##             ID["EPSG",9802]],
##         PARAMETER["Latitude of false origin",57.5175539305556,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8821]],
##         PARAMETER["Longitude of false origin",24,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8822]],
##         PARAMETER["Latitude of 1st standard parallel",59.3333333333333,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8823]],
##         PARAMETER["Latitude of 2nd standard parallel",58,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8824]],
##         PARAMETER["Easting at false origin",500000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8826]],
##         PARAMETER["Northing at false origin",6375000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8827]]],
##     CS[Cartesian,2],
##         AXIS["easting (Y)",east,
##             ORDER[1],
##             LENGTHUNIT["metre",1]],
##         AXIS["northing (X)",north,
##             ORDER[2],
##             LENGTHUNIT["metre",1]]]

Plot the DEM file

plot(DEM,col = terrain.colors(n=50))

DEM covers a big area while we need a small part of it. Rummu quarry is the small area in the bottom left corner of the figure. Create the polygon to clip DEM to the area of interest:

polygon <- as(extent(510800, 511300, 6565300, 6565750), 'SpatialPolygons')

crs(polygon) <- crs(DEM) # assign projection to the polygon

crs(polygon) # polygon and DEM have the same coordinate system
## Coordinate Reference System:
## Deprecated Proj.4 representation:
##  +proj=lcc +lat_0=57.5175539305556 +lon_0=24 +lat_1=59.3333333333333
## +lat_2=58 +x_0=500000 +y_0=6375000 +ellps=GRS80 +units=m +no_defs 
## WKT2 2019 representation:
## PROJCRS["Estonian Coordinate System of 1997 (with axis order normalized for visualization)",
##     BASEGEOGCRS["EST97",
##         DATUM["Estonia 1997",
##             ELLIPSOID["GRS 1980",6378137,298.257222101,
##                 LENGTHUNIT["metre",1]]],
##         PRIMEM["Greenwich",0,
##             ANGLEUNIT["degree",0.0174532925199433]],
##         ID["EPSG",4180]],
##     CONVERSION["Estonian National Grid",
##         METHOD["Lambert Conic Conformal (2SP)",
##             ID["EPSG",9802]],
##         PARAMETER["Latitude of false origin",57.5175539305556,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8821]],
##         PARAMETER["Longitude of false origin",24,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8822]],
##         PARAMETER["Latitude of 1st standard parallel",59.3333333333333,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8823]],
##         PARAMETER["Latitude of 2nd standard parallel",58,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8824]],
##         PARAMETER["Easting at false origin",500000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8826]],
##         PARAMETER["Northing at false origin",6375000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8827]]],
##     CS[Cartesian,2],
##         AXIS["easting (Y)",east,
##             ORDER[1],
##             LENGTHUNIT["metre",1]],
##         AXIS["northing (X)",north,
##             ORDER[2],
##             LENGTHUNIT["metre",1]]]
DEM_crop <- crop(DEM, polygon) # crop DEM by polygon

plot(DEM_crop,col = terrain.colors(n=50))

To use rayshader package, we need to convert DEM from raster to a matrix

DEM_matrix  <-  raster_to_matrix(DEM_crop)

Let’s try the first image:

DEM_matrix %>%
  sphere_shade(texture = "desert") %>% # `imhof1`,`imhof2`,`imhof3`,`imhof4`,`desert`, `bw`
  plot_map()