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.
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 "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/");
const loader = new GLTFLoader().setDRACOLoader(draco);
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 — 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
| Parameter | In | Type | Required | Default | Beschreibung |
|---|---|---|---|---|---|
bbox | query | string | yes | — | WGS84 minLon,minLat,maxLon,maxLat |
z_base | query | enum | no | per_building | per_building / bbox_min / absolute |
compression | query | enum | no | none | none / draco |
colorize_roofs | query | bool | no | false | Wall/Ground/Roof als separate Materials |
merge_buildings | query | bool | no | true | Alle Gebäude in 1 Mesh + Primitive-pro-Material |
target_frame | query | enum | no | utm | utm (UTM-Meter, Blender/DCC) / mercator (MapLibre-Scene-Units am Anchor, scenerii-App-kompatibel) |
origin | query | enum | no | center | center (bbox-Mitte) / corner (bbox-(minLon,minLat); überstehende Gebäude bleiben relativ korrekt) |
rotate_x | query | float | no | 0 | Rotation um X-Achse in Grad, intrinsisch vor Z |
rotate_z | query | float | no | 0 | Rotation um Z-Achse in Grad, intrinsisch nach X. Blender-Y-up: rotate_x=-90&rotate_z=-90 |
include_ground | query | bool | no | true | false = GroundSurface (class 710) weglassen, vermeidet Z-Fighting mit Boden-Layer |
weld_tolerance_m | query | float | no | 0.0 | Vertex-Merge-Toleranz (Quantize). 0 = aus; 0.01 schrumpft Stadt-Meshes um ~40 % |
Admin-Header
| Header | Beschreibung |
|---|---|
X-Lodapi-Admin-Token | Wenn 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 ummin(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:
| Header | Bedeutung |
|---|---|
ETag | für Conditional-GET |
Cache-Control | public, max-age=300 |
X-Lodapi-Buildings | Anzahl Gebäude im GLB |
X-Lodapi-Anchor-Srid | UTM-Anker-EPSG (z.B. 25832) |
X-Lodapi-Anchor-LonLat | lon,lat des Anchor-Punkts (WGS84) — bei origin=corner = minLon,minLat |
X-Lodapi-Origin-EN | E,N des Origin-Punkts im Anker-CRS |
X-Lodapi-Target-Frame | utm oder mercator |
X-Lodapi-Z-Base | gewähltes Z-Modell |
X-Lodapi-Compression | tatsächlich angewandte Compression (none / draco) |
X-Lodapi-Compression-Requested | angefragte Compression — Vergleich zu X-Lodapi-Compression signalisiert Fallback |
X-Lodapi-Compression-Error | nur gesetzt bei Fallback: kurze Fehler-Beschreibung |
X-Lodapi-Raw-Size | unkomprimierte Bytes (zum Vergleich) |
X-Lodapi-Max-Buildings | Server-Limit (20000 oder 1000000 bei Admin-Token) |
X-Lodapi-Admin-Limits | 1 wenn Admin-Bypass aktiv, sonst 0 |
Limits
| Limit | Public-Default | Mit X-Lodapi-Admin-Token |
|---|---|---|
bbox-Fläche | 1 km² | 250 km² |
| Gebäude-Count | 20 000 | 1 000 000 |
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=mercatorfür MapLibre-/Three.js-Setups, dieMercatorCoordinate.fromLngLat()als Scene-Basis nutzen (z. B. scenerii-App). UTM-Vertices in einem Mercator-Scene-Frame driften linear mit Entfernung vom Anchor wegensec(lat)-Stretch. origin=cornerfü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: falseerzeugt 1 Mesh progmlid— drastisch mehr Draw-Calls in Three.js. Defaulttrue(1 Mesh + Materials) ist fast immer richtig.- Compression-Fallback verifizieren: wenn
X-Lodapi-Compression: nonezurückkommt obwohl?compression=dracoangefragt war, sind die Bytes roh.X-Lodapi-Compression-Errorenthält die Ursache (typisch:gltf-pipelinenicht im Container-Image). include_ground=falsevermeidet Z-Fighting mit Boden-Layer in 3D-Viewern; GroundSurface ist eh selten sichtbar.
Verwandte Endpoints
GET /v1/buildings— FeatureCollection statt GLB.GET /v1/tilesets— 3D-Tiles-Streaming für große Flächen.