top of page

Shadow Maps: Winter shadows on a Black Forest map

Oct 13
6 min read

A free land cover map of the southern Black Forest, and where the mountains' shadows fall on it on the shortest day of the year.

A land cover map in dark green forest, yellow pasture, red villages and blue lakes, with sharp shadows lying north-west of every ridge: the forest darkened almost to black, the pastures to olive.

The southern Black Forest at 10:00 on 21 December, with the sun 12° above the south-eastern horizon. The frame is 27 km wide, from the Belchen near the left edge to the Titisee near the right, with the Feldberg in the middle and the edge of Freiburg in red in the top-left corner. Map data: ESA WorldCover 2021, shaded here.

At ten in the morning on the shortest day, the sun over the Feldberg, the highest summit in the Black Forest, stands 12° above the horizon. That is low enough for each ridge to put the next valley in shade. A land cover map knows nothing about light; it knows where the forest stops and the pasture begins, and that is what makes the shade easy to read on it. The yellow pastures turn olive, the forest turns almost black, and the villages strung along the valley floors go dark with them: at this hour two thirds of the built-up ground inside the outline lies in shade, against 64% of the forest and 52% of the pasture.

Below is how this render came about: one map, one outline and a handful of settings. Open Shadow Maps set to that morning. The map itself you make with one command and upload, because a file cannot travel in a link.

How this one got made

A map that knows where it is

Shadow Maps starts from a map with its coordinates inside it, a GeoTIFF. There is no box for typing coordinates; everything is read from the map itself. I built it that way to rule out a whole class of mistakes, such as a mismatched extent or the wrong hemisphere.

The European Space Agency's WorldCover map is such a file for the whole planet: every 10 m of land sorted into eleven classes, forest, grassland, cropland and built-up among them, free to use with a credit. It comes in tiles of 3° by 3°, far too big to upload, so cut your square straight out of the online tile with GDAL, without downloading the whole tile:

gdalwarp -t_srs EPSG:25832 -te 411100 5289500 437900 5316300 -ts 1500 1500 -r mode /vsicurl/https://esa-worldcover.s3.eu-central-1.amazonaws.com/v200/2021/map/ESA_WorldCover_10m_2021_v200_N45E006_Map.tif southern-black-forest.tif

It cuts a square of 26.8 km, given in metres, and resamples it to 1,500 × 1,500 pixels, 17.9 m each; mode keeps every pixel a single class. The file keeps WorldCover's colour table, and the app draws each class in its own colour. It is 2.3 MB, well under the app's 80 MB limit. For a place of your own, the tile is named after the south-west corner of its square, N45E006 for 45° to 48° north and 6° to 9° east, and EPSG:25832 becomes the UTM zone of your place. Upload the file under Georeferenced map (GeoTIFF).

An outline that rises off the page

Click the map at the corners of the area that should carry terrain, then press Finish polygon. Everything outside the outline stays flat. Everything inside is lifted, so its edges throw a drop shadow onto the map around it.

The app's drawing step: the land cover map with a thin orange rectangle drawn just inside its edges, and the buttons Undo point, Clear and Finish polygon below.

Four clicks, just inside the map's edge. The narrow strip outside the orange line is where the lifted block's drop shadow will land.

Opacity decides how much map survives

Press Render. The app downloads 30 m elevation data for the outline and lights it at the moment set under Time. Under Appearance, Shadow opacity starts at 1, which paints every shadow solid black and swallows the map underneath. The link lowers it to 0.6, and the shadows turn into a veil the land cover shows through. Shadow softness stays at 0, its default, so every edge stays as sharp as the elevation data allows.

Two crops of the same area around the Feldberg. Left: solid black shadow shapes covering most of the forest. Right: the same shadows as dark green and olive, the forest, the pastures and the small blue Feldsee all visible underneath.

Around the Feldberg at 10:00 on 21 December, with the summit's pasture in the middle and the Feldsee to its right. At opacity 1 on the left the shadows are holes in the map; at 0.6 on the right the land cover runs on underneath them.

I left out the usual hillshade on purpose. Cast shadows are the whole point of the piece, so the map only darkens where terrain stands between the ground and the sun.

December stretches every shadow

Set Date to 21 December and Hour (local) to 10:00, as the link does. The caption under the time controls reads the sun's position back to you: az 146°, alt 12°. For contrast, try 21 June at the same hour, when the sun stands 52° up.

Two square renders of the same map. Left, June: the map almost untouched. Right, December: sharp dark shadows across most of the valleys and north-facing slopes.

The same hour, half a year apart. In June less than 1% of the ground inside the outline lies in shade; in December 60%, filling the valleys and the slopes that face away from the sun.

One winter day, three hours

Keep December and move Hour (local) to 12:30, when the sun is near its highest, 19° up in the south, then to 15:00, 11° up in the south-west. Every shadow turns with it.

Three square renders of the same map at 10:00, 12:30 and 15:00 on 21 December: the shadows lie north-west of the ridges in the morning, shortest and due north at midday, and north-east in the afternoon.

10:00, 12:30 and 15:00 on 21 December. Even at midday 43% of the ground inside the outline lies in shade. At ten and at three the sun stands at almost the same height on either side of south, and about 60% does, the morning's shade thrown north-west of each ridge and the afternoon's north-east.

Average the whole day

Under Time, switch from Single time to Daily average. The app samples the sun every 30 minutes between the morning and evening golden hours and blends all the shadows into one exposure. Every one of those shadows is cast, so first set Shadow quality under Appearance to Fast (700). The daily render then took a little over two minutes. Yearly average does the same on twelve days spread across the year, every two hours: 72 sun positions and about six minutes.

Three square renders of the whole map. Left: crisp shadows next to brightly lit ground. Middle: nearly everything dimmed, with darker patches in the valleys. Right: a lighter, even dimming with the deepest valleys still dark.

The whole map at Shadow quality Fast: one moment, one December day, one year. One moment puts sharp shadows next to fully lit ground. One December day dims nearly everything, the deep valleys most. Over a year the summer sun reaches more of the slopes, and the shade settles into a lighter, even dimming.

The averaging revives a lost R script I used to work from. Whatever the period, the ground inside the outline that spends the most time in shadow is drawn as dark as a single shadow, so even a year of sun keeps some contrast. Shadow Maps is an aesthetic instrument first.

How the shadow is cast

For every cell of the elevation grid, the app follows a line towards the sun, climbing at the sun's angle, and asks whether terrain gets in the way. If it does, the cell is in shadow. Vertical exaggeration multiplies the heights before that test, which is why 2, the default, gives longer shadows than the real mountain would.

Two side-view elevation profiles through the Feldberg. Top: the ground in shadow marked red, and a dashed line from a shadowed point that climbs towards the sun and runs into the summit. Bottom: the same profile with the ground outside a marked outline set flat, and a red stretch of flat ground on the left, the lifted block's drop shadow.

Computed with the app's own shadow code from the same 30 m data, along the line of the 10:00 December sun, heights doubled. Top: most of the north-north-west flank lies in shade, and the dashed line shows why for one point. Bottom: the lift, and the drop shadow it throws.

From screen to object

Under Downloads, tick the terms and Shadow map (PNG) gives you the finished map as a PNG, at most A5 at 300 dpi. Sources and credits names the elevation data behind it, and Order a print of this creation lets you order it on paper.

The Downloads section of the app: a full-width Shadow map (PNG) button, then folds for Sources and credits and Order a print of this creation.

The whole list a visitor sees after ticking the terms: one file, then two folds.

Other controls, one line each

  • Under Time, Monthly average spreads the average over ten days of the month, and Golden hour samples an hour centred on the morning or evening golden hour.

  • Shadow softness blurs the shadow edges, for a gentler veil.

  • Elevation highlight and Sun highlight make the peaks, or the sunniest ground, glow in the Highlight colour.

  • Source under Elevation takes your own, finer elevation file instead of the 30 m download.

  • + Add elevated area, under Add elevated areas (optional), raises a drawn shape, a legend box say, by Plateau height (m), so it casts a shadow of its own.

Map data in this post: ESA WorldCover 10 m 2021 v200, © ESA WorldCover project 2021 / Contains modified Copernicus Sentinel data (2021) processed by ESA WorldCover consortium, CC BY 4.0; reprojected, resampled and shaded in Shadow Maps.

Your turn

A print of any render can be ordered from the same Downloads list.

Open Shadow Maps set to that morning, upload a map of a place you know, and change one thing: the date of your birthday, or the hour you usually walk there. Then send me what you made. I'll ask before I show it anywhere.

Next: the same 27 km square read a second way, in bricks, in The Feldberg, read in light and in bricks.

 
 
bottom of page