GET /v1/buildings/3d.glb

Bbox → einzelnes GLB (z-normalisiert, föderiert)

stable seit v0.1.0 buildings auth: api_key · ab hobby

Beispiel-Ergebnis

So sieht die Antwort aus

Das gelieferte GLB-Modell der Frankfurter Innenstadt als hellbeiges 3D-Stadtmodell mit Schattenwurf, im Vordergrund Hochhäuser.
Dieselbe Bbox als eine einzige Datei: 643 KB model/gltf-binary, 351 Gebäude (Header x-lodapi-buildings), z per Gebäude normalisiert. Die Datei wurde unverändert geladen. Gerendert aus der echten API-Antwort, kein Mockup. Daten: © Hessisches Landesamt für Bodenmanagement und Geoinformation (HLBG) (Wortlaut aus /v1/attribution (buildings, he; dl-de-zero-2.0))

Aufruf

curl -G https://api.lodapi.de/v1/buildings/3d.glb \
  -H "X-API-Key: $LODAPI_KEY" \
  -d bbox=8.66,50.108,8.665,50.111 \
  -o frankfurt.glb -D -

Response-Header (Auszug), der Body ist die GLB-Datei

HTTP/2 200
content-type: model/gltf-binary
content-length: 658568
cache-control: public, max-age=300
x-lodapi-buildings: 351
x-lodapi-max-buildings: 20000
x-lodapi-raw-size: 658568
x-lodapi-compression: none
x-lodapi-target-frame: utm
x-lodapi-anchor-srid: 25832
x-lodapi-anchor-lonlat: 8.662500,50.109500
x-lodapi-origin-en: 475867.368,5550860.064
x-lodapi-z-base: per_building
…

Darstellung: three.js GLTFLoader. Material und Kantenlinien von uns überschrieben, die Geometrie ist unverändert.

GET /v1/buildings/3d.glb — Bbox als einzelnes GLB

Bündelt alle Gebäude einer WGS84-Bbox in eine einzige binäre glTF-Datei (model/gltf-binary). Ready für Three.js, Blender, QGIS-3D-Map-Plugins. Koordinaten sind im lokalen ENU-Frame (East-North-Up, Origin im bbox-Center). Z ist per default per-Building-normalisiert — jedes Gebäude steht „auf Z=0”.

Optional: Draco-Kompression (18-bit Position-Quantization), Material-pro-Surface-Klasse (Wall/Ground/Roof), Merging-Modus.

Zugang

Ab Tarif Hobby, mit API-Key im Header X-API-Key. Ohne Key antwortet der Endpoint mit 401, mit einem Key unter Hobby mit 403 (beides application/problem+json, mit Link auf Key bzw. Tarife). Einen Testkey bekommst du in einer Minute unter lodapi.de/key: 7 Tage gültig, Pro-Umfang, ohne Registrierung. Die Beispiele unten lesen den Key aus der Umgebungsvariable LODAPI_KEY.

Wann verwenden

  • Architektur-Visualisierung / 3D-Konfiguratoren (z.B. PV-Tool, Bebauungsplan-Browser).
  • Blender-Import für Renderings.
  • Three.js-Scene ohne 3D-Tiles-Streaming-Komplexität.

Für streaming/large-area-Rendering ist /v1/tilesets der bessere Pfad. 3d.glb ist für statisch-bbox-Use-Cases.

Examples

curl

curl -s -H "X-API-Key: $LODAPI_KEY" \
  "https://api.lodapi.de/v1/buildings/3d.glb?bbox=8.66,50.108,8.665,50.111&compression=draco&colorize_roofs=true" \
  > frankfurt-block.glb

Three.js — Drop-in-Loader

import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";

const draco = new DRACOLoader();
draco.setDecoderPath("https://www.gstatic.com/draco/v1/decoders/");
// Key nur in internen Tools/Server-Kontexten einbetten, nie in öffentlichem Frontend-Code.
const loader = new GLTFLoader()
  .setDRACOLoader(draco)
  .setRequestHeader({ "X-API-Key": LODAPI_KEY });

const url = "https://api.lodapi.de/v1/buildings/3d.glb?bbox=8.66,50.108,8.665,50.111&compression=draco";
const gltf = await loader.loadAsync(url);
scene.add(gltf.scene);

Python-SDK

# pip install lodapi
import os

from lodapi import Client

with Client(api_key=os.environ["LODAPI_KEY"]) as c:
    c.buildings.glb(
        bbox=(8.66, 50.108, 8.665, 50.111),
        compression="draco",
        out="frankfurt-block.glb",
    )

Python — Offline-Variante

# Pure offline-Skript ohne API-Roundtrip, gleicher Output:
uv run python bin/scenerii_bbox_export.py \
  --bbox 8.66,50.108,8.665,50.111 \
  --out frankfurt-block.glb \
  --draco --draco-position-bits 18 \
  --colorize-roofs

Parameters

ParameterInTypeRequiredDefaultBeschreibung
bboxquerystringyes—WGS84 minLon,minLat,maxLon,maxLat
z_basequeryenumnoper_buildingper_building / bbox_min / absolute
compressionqueryenumnononenone / draco
colorize_roofsqueryboolnofalseWall/Ground/Roof als separate Materials
merge_buildingsqueryboolnotrueAlle Gebäude in 1 Mesh + Primitive-pro-Material
target_framequeryenumnoutmutm (UTM-Meter, Blender/DCC) / mercator (MapLibre-Scene-Units am Anchor, scenerii-App-kompatibel)
originqueryenumnocentercenter (bbox-Mitte) / corner (bbox-(minLon,minLat); überstehende Gebäude bleiben relativ korrekt)
rotate_xqueryfloatno0Rotation um X-Achse in Grad, intrinsisch vor Z
rotate_zqueryfloatno0Rotation um Z-Achse in Grad, intrinsisch nach X. Blender-Y-up: rotate_x=-90&rotate_z=-90
include_groundqueryboolnotruefalse = GroundSurface (class 710) weglassen, vermeidet Z-Fighting mit Boden-Layer
weld_tolerance_mqueryfloatno0.0Vertex-Merge-Toleranz (Quantize). 0 = aus; 0.01 schrumpft Stadt-Meshes um ~40 %

Admin-Header

HeaderBeschreibung
X-Lodapi-Admin-TokenWenn gesetzt + Match gegen Server-LODAPI_ADMIN_TOKEN: erlaubt bis 250 km² / 1 000 000 Buildings (statt 1 km² / 20 000). Server-zu-Server only, kein Public-Sharing.

Z-Normalization

  • per_building (Default): jedes Gebäude steht auf Z=0. Konsistente Höhe-über-Boden für Visualizer, ideal für scenerii-style-Apps.
  • bbox_min: alle Gebäude verschoben um min(z) der bbox. Gelände bleibt erkennbar, Bbox-Boden auf Z=0.
  • absolute: original DHHN2016-NHN-Werte. Für GIS-Werkzeuge mit Terrain-Kontext.

Response

200 OK · model/gltf-binary — eine GLB-Datei.

Antwort-Header tragen Metadata:

HeaderBedeutung
ETagfür Conditional-GET
Cache-Controlpublic, max-age=300
X-Lodapi-BuildingsAnzahl Gebäude im GLB
X-Lodapi-Anchor-SridUTM-Anker-EPSG (z.B. 25832)
X-Lodapi-Anchor-LonLatlon,lat des Anchor-Punkts (WGS84) — bei origin=corner = minLon,minLat
X-Lodapi-Origin-ENE,N des Origin-Punkts im Anker-CRS
X-Lodapi-Target-Frameutm oder mercator
X-Lodapi-Z-Basegewähltes Z-Modell
X-Lodapi-Compressiontatsächlich angewandte Compression (none / draco)
X-Lodapi-Compression-Requestedangefragte Compression — Vergleich zu X-Lodapi-Compression signalisiert Fallback
X-Lodapi-Compression-Errornur gesetzt bei Fallback: kurze Fehler-Beschreibung
X-Lodapi-Raw-Sizeunkomprimierte Bytes (zum Vergleich)
X-Lodapi-Max-BuildingsServer-Limit (20000 oder 1000000 bei Admin-Token)
X-Lodapi-Admin-Limits1 wenn Admin-Bypass aktiv, sonst 0

Limits

LimitPublic-DefaultMit X-Lodapi-Admin-Token
bbox-Fläche1 km²250 km²
Gebäude-Count20 0001 000 000

Ohne X-API-Key: 401; mit Key unter Hobby: 403 (siehe Zugang). Der Admin-Token ersetzt den Key für Server-zu-Server-Aufrufe.

Bei Überschreitung: 413 Payload Too Large. Public-Limit-Fehlermeldung enthält Hint or supply X-Lodapi-Admin-Token.

Stolperdrähte

  • Draco-Default-Quantization von gltf-pipeline ist 11 bit (~5 m Auflösung bei 10 km bbox) — Lodapi nutzt 18 bit (3,8 cm @ 10 km), sonst zerlegt Draco die Geometrie sichtbar. Wenn du eigene Draco-Codecs schaltest, halt mind. 18 bit ein.
  • Frame-Wahl ist Konsumenten-spezifisch: target_frame=utm (Default) für Blender/DCC/Cesium-ENU; target_frame=mercator für MapLibre-/Three.js-Setups, die MercatorCoordinate.fromLngLat() als Scene-Basis nutzen (z. B. scenerii-App). UTM-Vertices in einem Mercator-Scene-Frame driften linear mit Entfernung vom Anchor wegen sec(lat)-Stretch.
  • origin=corner für Tile-Style-Mounts: überstehende Gebäude erhalten dann leicht negative Vertex-Koordinaten — das ist absichtlich, damit ihre Position relativ zur BBox-Ecke korrekt bleibt.
  • merge_buildings: false erzeugt 1 Mesh pro gmlid — drastisch mehr Draw-Calls in Three.js. Default true (1 Mesh + Materials) ist fast immer richtig.
  • Compression-Fallback verifizieren: wenn X-Lodapi-Compression: none zurückkommt obwohl ?compression=draco angefragt war, sind die Bytes roh. X-Lodapi-Compression-Error enthält die Ursache (typisch: gltf-pipeline nicht im Container-Image).
  • include_ground=false vermeidet Z-Fighting mit Boden-Layer in 3D-Viewern; GroundSurface ist eh selten sichtbar.

Verwandte Endpoints

Verwandt

  • /v1/buildings
  • /v1/tilesets

Bereit?

Der erste Call geht sofort.

LoD2-Gebäude für alle 16 Bundesländer, kostenlos und ohne Konto. Pro auf Anfrage 30 Tage testen.