---
operation_id: get_buildings_glb
method: GET
path: /v1/buildings/3d.glb
summary: Bbox → einzelnes GLB (z-normalisiert, föderiert)
tags: [buildings]
stability: stable
since_version: 0.1.0
auth: none
data_product: buildings
snapshot_aware: true
attribution_block: false
rate_limit_tier: public
related:
  - /v1/buildings
  - /v1/tilesets
---
# `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

```bash
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

```ts
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

```bash
# 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 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:

| 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=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

- [`GET /v1/buildings`](./list-buildings-bbox.md) — FeatureCollection statt GLB.
- [`GET /v1/tilesets`](./list-tilesets-bbox.md) — 3D-Tiles-Streaming für große Flächen.