Fundierte Artikel über Technologien, die das Kommende formen.

Die ganze Schweiz als Voxel: Eine Geodaten-Pipeline

Wie eine Voxel-Pipeline Schweizer Open Geodata in eine 1:1-Minecraft-Welt verwandelte, mit Lehren zu Kacheln, Level of Detail und Streaming räumlicher Daten.

Voxel-Alpental mit klotzigem Gletscher und treppenförmigen kubischen Bergspitzen.
Ein Block, ein Meter: ein ganzes Land, aus offenen Geodaten von Behörden als Voxel nachgebaut.

Irgendwo im Open-Data-Portal der Schweizer Regierung liegt eine Höhenkarte der Eiger-Nordwand, fein genug abgetastet, dass man den Fels förmlich spürt. Ein Entwickler fütterte Dateien wie diese in eine Voxel-Pipeline und lieferte das Ergebnis als spielbares Produkt aus: die gesamte Schweiz als 1:1-Minecraft-Welt, in der jeder Block einen Meter misst und das Matterhorn genau so hoch und so steil steht wie das echte. Der Download ist 24 GB gezippt, und allein die kostenlose Proberegion umfasst rund 2.400 km². Die Technik darunter, also Kachelung, Level of Detail und verzögerte Generierung, ist ein Meisterkurs darin, riesige Geodatensätze zu bewegen, ohne dass alles in Flammen aufgeht.

Das Problem: Ein Land aus Voxeln passt nicht in den Speicher

Rechnen wir einfach mal nach. Die Schweiz hat 41.285 km². Bei einem Block pro Quadratmeter sind das 41,3 Milliarden Oberflächensäulen, noch bevor du ein einziges Loch gegraben hast. Gibst du jeder Säule bescheidene 100 Blöcke Tiefe, also Gestein, Erde und Seebett, bist du bei vier Billionen Blöcken. Selbst bei einem Byte pro Block sind das vier Terabyte reine Geometrie. Trotzdem wird die fertige Welt als 24-GB-Download ausgeliefert, und das verrät etwas Wichtiges: Fast nichts davon wird als Geometrie gespeichert. Es wird als Rezept gespeichert.

Auch die vertikale Achse macht Probleme. Vanilla-Minecraft begrenzt die Welt auf 384 Blöcke Bauhöhe. Die Schweiz reicht vom Lago Maggiore auf 193 m über dem Meer bis zur Dufourspitze auf 4.634 m. Das ist eine Spanne von 4.441 m, mehr als das Elffache des Vanilla-Limits, und dabei hat noch niemand einen Stollen gegraben. Deshalb braucht die Welt Cubic Chunks, einen Mod, der Minecrafts spaltenbasierte Speicherung durch 16×16×16-Würfel ersetzt, die so hoch gestapelt werden, wie es nötig ist. Dieser Mod läuft nur stabil auf Minecraft Java 1.12.2. Deshalb ist ein Projekt, das heute ausgeliefert wird, an eine Spielversion gebunden, die schon Jahre alt ist.

Die dritte Mauer ist der Arbeitsspeicher. Blöcke aus den Quelldaten zu erzeugen, wenn ein Spieler ein Gebiet zum ersten Mal betritt, ist rechenintensiv: Das Projekt verlangt mindestens 16 GB RAM und wird auf Rechnern wie einem Ryzen 7 7800X3D mit 32 GB getestet. Wer schon mal mit Streaming-Budgets in Spielen oder GIS gekämpft hat, erkennt das Muster sofort. Es ist dieselbe Priorisierung, die du brauchst, wenn deiner GPU der VRAM ausgeht. Du kannst nicht alles halten, also wirst du sehr gut darin, zu entscheiden, was du gerade halten musst.

Erster Fehlversuch: Die ganze Welt vorab backen

Der naheliegende Ansatz ist ein großer Offline-Job: Geodaten einlesen, Minecraft-Region-Dateien erzeugen (das Anvil-Format speichert die Welt in Regionen von 512×512 Blöcken), das Ergebnis zippen und ausliefern. Dänemark hat 2014 etwas Ähnliches gemacht, als die Danish Geodata Agency das gesamte Land als Minecraft-Karte veröffentlichte. Das war eine wegweisende Open-Data-Demo und bewies, dass eine landesweite Karte möglich ist. Warum also nicht dieser Weg?

Weil Vorab-Backen strukturelle Kosten hat, die mit dem Ehrgeiz wachsen. Jeder Block jeder Region muss erzeugt, geschrieben und komprimiert werden, bevor überhaupt jemand spielt. Dadurch wird jede Datenaktualisierung zu einem vollständigen Neuaufbau plus einem erneuten Versand von zig Gigabyte. Jeder Spieler lädt Gebirge herunter, die er nie besuchen wird, und die meisten der 41.000 km² wird ohnehin niemand je betreten. Am schlimmsten: Eine gebackene Welt friert im Moment der Veröffentlichung auf den Datenstand ein. Sie ist ein Artefakt, das man nur einmal schreiben kann. Sie verbessert sich nicht, es sei denn, du generierst alles neu und verteilst es erneut, und deine Nutzer laden den ganzen Planeten noch einmal herunter.

Zweiter Fehlversuch: Eine Höhenkarte in einer einzigen Auflösung

Die zweite Versuchung ist die Normalisierung: Alle Eingaben werden in ein einziges globales Raster mit einer einzigen Auflösung umgewandelt, damit die Pipeline genau einen Codepfad hat. In der Schweiz gibt es swissALTI3D, ein hochauflösendes Geländemodell. Jenseits der Grenze gibt es das Copernicus GLO-30 DEM, also einen Höhenpunkt alle 30 Meter. Reduzierst du alles auf 30 m, damit es einheitlich wird, verwandelt sich die Eiger-Nordwand in einen treppenförmigen Sandhaufen. Rechnest du alles auf die feinste verfügbare Auflösung hoch, explodieren Speicher und Verarbeitung, während die Grenzregionen trotzdem keine echten Daten enthalten. Du hast nur deine Unwissenheit hochgerechnet.

Heterogenität trifft die Semantik genauso hart wie die Höhe. swissBUILDINGS3D deckt die Schweiz ab, sodass der Generator vereinfachte Voxel-Gebäude auf echten Grundrissen errichten kann, aber nur innerhalb des Landes. Überquerst du die Grenze bei Genf, gibt es gar keine Gebäudeebene. Also macht die Pipeline das einzig Vernünftige als Ersatz: Sie pflanzt Bäume, wo Häuser stehen sollten. Wasser braucht eine eigene Quelle (swissBATHY3D für Seeböden), ebenso Gletscher, Wälder und Weinberge. Es gibt keine einzelne Eingabedatei. In Geodaten gibt es nie eine.

Die Lehre reicht weit über Minecraft hinaus: Die Auflösung ist eine Metadaten-Eigenschaft pro Kachel, keine globale Konstante. Eine Pipeline, die einheitliche Eingaben voraussetzt, verschenkt entweder Detailtreue oder erfindet sie. Erfundene Detailtreue ist aber schlimmer als ehrliche Grobheit, weil von innen niemand den Unterschied erkennt.

Ein Raster aus Kartenkacheln fließt durch einen Trichter und entsteht als zusammengesetzte Voxel-Landschaft.
Die zentrale Umkehr: Daten als Kacheln und Rezepte halten und Blöcke nur dort zusammensetzen, wo tatsächlich jemand hingeht.

Was tatsächlich funktioniert: Eine gekachelte Pipeline, die verzögert generiert

Das Schweizer Projekt funktioniert, weil es den Instinkt, alles vorab zu backen, umdreht. Du lädst keine fertige Welt herunter, sondern ein Welt-Paket, also vorverarbeitete Geodaten plus einen eigenen Generator. Das Spiel baut die Blöcke erst, wenn du einen Ort zum ersten Mal wirklich besuchst. Ein erster Besuch in einem neuen Gebiet dauert ein paar Minuten Rechenarbeit, danach sind es zwischengespeicherte Chunks wie bei jeder anderen Minecraft-Welt. Die Rechenzeit fällt pro Besuch an statt im Voraus, und Gelände, auf dem niemand steht, wird nie generiert. Die Kachel ist die Einheit für alles: Speicherung, Caching, Generierung und Fehlerbehandlung.

Die Kachelung ist an LV95 verankert, das offizielle Landesvermessungs-Koordinatensystem der Schweiz. Jede Kachel vermerkt, welche Datensätze sie abdecken und in welcher Auflösung. Die Umrechnung von Vermessungskoordinaten in Blockkoordinaten ist eine reine affine Transformation. Das Projekt veröffentlicht sogar die Formel, damit du Koordinaten aus dem nationalen Kartenviewer übernehmen und im Spiel an die passende Stelle teleportieren kannst:

def lv95_to_block(east: float, north: float, height: float) -> tuple[int, int, int]:
"""Convert Swiss LV95 survey coordinates to Minecraft block coordinates."""
x = int(east - 2_480_000)   # strip the LV95 easting offset
z = int(1_300_000 - north)  # Minecraft's z axis grows southward
y = int(height)             # one block = one meter above sea level
return x, y, z
# The summit of the Jungfrau, 4,158 m:
print(lv95_to_block(2_640_188, 1_154_072, 4158))
# -> (160188, 4158, 145928)
# x and z match the in-game teleport command exactly; the game just
# drops you a few meters higher so you land on the summit, not in it.

Über dem gekachelten Raster ist die Generierung ein Schichtstapel, der pro Spalte ausgewertet wird. Die Basishöhe stammt aus swissALTI3D. Die Oberflächenbedeckung, also Wasser, Wald, Straßen, Bahnlinien, Dämme und Lawinenverbauungen, kommt aus swissTLM3D. Seeböden stammen aus swissBATHY3D, Baumhöhen aus swissSURFACE3D, Gletscherumrisse aus den GLAMOS-Inventaren bis 1850 zurück und die Eisdicke aus einem Datensatz der ETH Zürich. So ist der Aletschgletscher tatsächlich ausgehöhltes Eis und nicht bloß eine weiße Textur auf dem Fels. Wiesen, Geröllhalden und Weinberge stammen aus der Lebensraumkarte des Bundes, und selbst Zürichs Straßenbäume kommen aus dem eigenen Baumkataster der Stadt. Insgesamt sind es etwa fünfzehn offene Datensätze, alle frei nutzbar. swisstopo hat seine Daten 2021 geöffnet, auch für kommerzielle Nutzung.

Eine Voxel-Welt ist kein Bild von Gelände. Sie ist ein Cache aus Millionen kleiner Entscheidungen, die deine Pipeline getroffen hat, eine pro Quadratmeter. Und die Qualität der Welt entspricht genau der Qualität dieser Entscheidungen.

Level of Detail ist ein Datenproblem, kein Rendering-Trick

Die Standard-Sichtweite von Minecraft zeigt dir ein paar hundert Meter. Die Screenshots des Projekts zeigen dagegen den Aletschgletscher, der sich kilometerweit ins Land schwingt. Diese Fernsicht ist eine eigene, reduzierte Darstellung, die das Spiel beim ersten Start einmal aufbaut. Das ist klassisches Level of Detail, doch die wichtige Entscheidung liegt darin, wo das LOD lebt: Es wird beim Einlesen aus den Quelldaten berechnet und nicht vom Renderer im Flug zurechtgebogen.

Wer schon Kachel-Pyramiden für Karten gebaut hat, kennt die Rechnung. Jede Zoomstufe halbiert die Auflösung in beide Achsen, also kostet eine volle Pyramide 1 + 1/4 + 1/16 + … ≈ 4/3 der Basisebene. Das ist ein Speicheraufschlag von 33 % für sauberes Verhalten auf jeder Skala. Voxel-LOD ist im Grunde dieselbe Pyramide, nur aufrecht gestellt: Fernes Gelände ist die grobe Zoomstufe, nahes die feine. Die eigentliche Kunst liegt darin, ein Schlüsselschema zu wählen, mit dem du die richtige Zelle schnell abrufen kannst. Dieselben Fragen kennen wir von den Abwägungen zwischen Geohashes und richtigen räumlichen Indizes. Die Wahl des Schlüssels bestimmt überall flussabwärts die Kosten jeder Abfrage.

Meine Lieblingsentscheidung hier ist überhaupt nicht visuell. Der kostenlose Download ist ein 2.400-km²-Ausschnitt, die UNESCO-Region Jungfrau-Aletsch mit Eiger, Mönch, Jungfrau und dem größten Gletscher der Alpen. Er durchläuft exakt dieselbe Pipeline wie das bezahlte Gesamtland. Das ist ein Canary-Release als Produktfeature. Er hat 1,1 GB statt 24, erfordert keine Anmeldung, und wenn er auf deinem Rechner läuft, läuft die volle Karte auch. Wenn du große Datenprodukte baust, kopiere das ruhig: Deine kostenlose Stufe sollte ein repräsentativer Ausschnitt deines schwierigsten Geländes sein, keine verkrüppelte Demo deines einfachsten.

Voxel-Berge, die vorne aus feinen kleinen Blöcken bestehen und in der dunstigen Ferne in grobe, riesige Blöcke übergehen.
Fernes Gelände ist einfach die grobe Zoomstufe derselben Pyramide. Das LOD wird beim Einlesen festgelegt, nicht vom Renderer.

Streaming gekachelter Geodaten im Browser

Dieselbe Disziplin zeigt sich auf der unscheinbaren Webseite des Projekts. Die Übersichtskarte lässt dich mit einem Schieberegler die Voxel-Welt mit dem echten Luftbild vergleichen, und die Bilder kommen überhaupt nicht von den Servern des Projekts. Dein Browser lädt SWISSIMAGE-Kacheln direkt vom eigenen Dienst von swisstopo, und zwar erst, wenn du den Schieberegler bewegst. Lazy, direkt vom Ursprung, cache-freundlich: Die große Bandbreite übernimmt öffentliche Infrastruktur, die genau dafür existiert, und die Hosting-Rechnung des Projekts bleibt nahe null.

Die Adressierung von Kacheln im Web ist ein gelöstes Problem, und es lohnt sich, sie im Schlaf zu beherrschen, falls du jemals mit Geodaten arbeitest:

import math
def latlon_to_tile(lat: float, lon: float, zoom: int) -> tuple[int, int]:
"""Standard slippy-map (XYZ) tile addressing used by OSM and most WMTS fronts."""
n = 2 ** zoom
x = int((lon + 180.0) / 360.0 * n)
lat_rad = math.radians(lat)
y = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)
return x, y
# At zoom 15, any point on Earth lands in one of 1,073,741,824 tiles.
# Fetch the few that intersect the viewport. Skip the other billion.

Zwei Details wiegen schwerer als die Formel. Erstens wird die Anfrage aufgeschoben, bis die Absicht des Nutzers eindeutig ist, also bis der Schieberegler wirklich bewegt wird. Das ist sowohl eine Bandbreitenoptimierung als auch eine Höflichkeit gegenüber einem kostenlosen öffentlichen Dienst, der mit öffentlichen Mitteln betrieben wird. Zweitens reist die Herkunftsangabe mit den Kacheln: Die Seite nennt SWISSIMAGE, swissBOUNDARIES3D und swissNAMES3D direkt an der Karte. Wenn dein Produkt ein abgeleitetes Werk offener Daten ist, ist die Namensnennung an der Stelle der Anzeige keine Dekoration. Sie ist die Lizenz, die so funktioniert, wie sie soll.

Was du von der Schweizer Pipeline übernehmen solltest

Zuerst die Gegenargumente, denn Praktiker haben gute vorgebracht. Handgebaute Projekte wie Build the Earth lassen Tausende Freiwillige echte Gebäude modellieren, und keine automatisierte Pipeline erreicht diese Detailtreue. Ein voxelisierter swissBUILDINGS3D-Grundriss ist eine grobe Näherung, und wenn dir Architektur wichtig ist, ist ein reiner Gelände-Export wohl das sauberere Artefakt. Fair. Aber Abdeckung und Detailtreue stehen im direkten Zielkonflikt: Automatisierung liefert dir heute 41.285 km², Handarbeit irgendwann eine wunderschöne Altstadt. Meine Position: Für ein Datenprodukt gewinnt die automatisierte Generierung mit veröffentlichter Herkunftsangabe, und handgebaute Landmarken können dort obendrauf, wo sie wirklich zählen.

Und die Herkunftsangabe ist der Teil, den alle überspringen. Dieses Projekt liefert eine Liste bekannter Fehler mit: Lücken nahe den Grenzen, wo nur das 30-m-Copernicus-Raster hinkommt, lückenhafte oder flache Stellen, falsche oder fehlende Brücken und Straßen, und QA per Stichprobe statt Meter für Meter. Diese Liste leistet echte Arbeit. Sie verwandelt Fehlerberichte der Art „Deine Welt ist hier falsch“ in Dokumentation der Art „Ja, der Datensatz endet dort“. Jedes abgeleitete Datenprodukt sollte seine Herkunftsmatrix und seine Liste bekannter Fehler veröffentlichen. Die, die das nicht tun, sind nicht genauer, sie sind nur weniger ehrlich.

  • Alles kacheln. Die Kachel ist deine Einheit für Speicherung, Caching, Generierung und Fehler. Monolithen degradieren nicht sanft.
  • Beim Einlesen nie herunterskalieren. Behalte die native Auflösung jeder Quelle und rechne erst beim Rendern um.
  • Verzögert generieren. Sobald die Welt größer ist als die Spielzeit irgendjemandes, schlägt Rechnen pro Besuch das Vorab-Backen.
  • Die LOD-Pyramide beim Einlesen aufbauen. Plane den Aufschlag von etwa 33 % ein und erkaufe dir sauberes Skalieren auf jeder Distanz.
  • Einen Canary-Ausschnitt ausliefern. Ein kostenloser, repräsentativer Teil deiner schwierigsten Daten schlägt jedes Datenblatt.
  • Herkunft und bekannte Fehler veröffentlichen. Sie sind Teil des Produkts, keine Entschuldigung dafür.

Das komplette Land kostet 15 CHF inklusive aller künftigen Versionen, und zwar nur für Schweizer Einwohner, aus rechtlichen Gründen. Für ein rein digitales Gut ist das eine erstaunlich charmante Einschränkung. Das eigentliche Produkt ist aber nicht die Karte. Es ist der Beweis, dass eine einzelne Person mit öffentlichen Daten, einer gekachelten Pipeline und ehrlicher Dokumentation die Geodaten-Infrastruktur der meisten Teams überholen kann. Dein Datensatz umfasst wahrscheinlich nicht 41.285 km². Deine Ausreden sind übrigens auch kleiner.