3D Tiles format: OGC 1.1 streaming 3D cities — OSM export to Cesium tileset
3D Tiles is the OGC standard for streaming large 3D datasets to the browser: city models with millions of buildings, photogrammetry meshes from drone scans, LiDAR point clouds, federated BIM models. Unlike a single glTF/GLB file loaded in full, 3D Tiles splits the scene into a hierarchical tree of tiles with level-of-detail (LOD) and bounding volumes — the client pulls only tiles visible in the current frustum and only at the detail level required for the current camera distance. That's how Google Earth 3D, Cesium ion, and ArcGIS Scene Service serve terabyte-scale 3D datasets through plain HTTP without any application server. On osm2cdr.ru tiles3d_exporter.py takes PostGIS buildings from OSM data, runs them through Building3DExporter for extrusion to height, splits them into spatial chunks, generates glTF 2.0 binary for each chunk, and assembles tileset.json with a bounding volume tree — ready for hosting on CloudFlare R2 or Cesium ion and viewing through CesiumJS.

History: from Cesium GS 2015 to OGC 1.1 (2023)
3D Tiles was born inside Cesium GS — a company founded in 2012 by Patrick Cozzi and a group of Analytical Graphics Inc. engineers who built the CesiumJS WebGL library for browser geodata viewing. By 2015 it was clear: CesiumJS rendered small scenes beautifully but choked on massive 3D cities — loading the full New York City model killed the browser before the user saw a single pixel.
In August 2015 the Cesium team published the first 3D Tiles specification — an open format for hierarchical streaming of 3D geospatial data. The idea was borrowed from the games world (HLOD — Hierarchical Level of Detail from Unreal Engine and Quake) and from web mapping (XYZ tiles from Google Maps / OSM): split the 3D scene into a tree of tiles where the root is a low-detail version of the entire scene and the leaves are full-detail chunks. The client recursively walks the tree, renders large tiles for distant objects and fine tiles for nearby ones.
By 2018 3D Tiles 1.0 was adopted by OGC as a Community Standard. It was OGC's compromise category — not a full standard, but an officially recognized specification with an open process. Inside 1.0: four content tile formats — b3dm (Batched 3D Model, binary glTF with per-feature metadata), i3dm (Instanced 3D Model, for repeating objects like trees), pnts (Point Cloud, for LiDAR), cmpt (Composite, a container for several tiles in one file).
In September 2023 OGC ratified 3D Tiles 1.1 as a full OGC Standard (document 22-025r4). The key change: native glTF 2.0 as content format. Proprietary b3dm/i3dm/cmpt remain for backward compatibility, but new tilesets use pure .glb with two glTF extensions: EXT_mesh_features (per-feature IDs for batching buildings) and EXT_structural_metadata (semantic schema — building types, materials, floor counts). That simplified the ecosystem — any glTF viewer can now partially read a 3D Tiles 1.1 tile.
Inside the tileset: bounding volume tree
The root of a 3D Tiles tileset is a tileset.json file, a JSON document describing the hierarchical tree of spatial tiles. Each tree node is a tile object with these fields: boundingVolume (region/box/sphere — the tile's spatial volume in WGS84), geometricError (a number in meters — the geometric error estimate from rendering this tile instead of its children), refine (REPLACE or ADD), content (optional — URI to the binary tile), children (array of child tiles).
Bounding volume. Three kinds: region (WGS84 lat/lon/min-height/max-height box, for geographic data), box (an oriented bounding box in a local frame, for photogrammetry), sphere (center + radius, the simple case). The client uses bounding volume for frustum culling — if the volume doesn't intersect the camera frustum, the whole subtree is skipped without fetching.
Screen-space error (SSE). The main 3D Tiles display algorithm: for every tile the client projects geometricError onto the screen in pixels. If SSE > threshold (typically 16 px), the tile renders at its current LOD. If SSE < threshold, children load and render in place of the parent. That's how LOD streaming works automatically: nearby objects pull in at high detail, distant ones stay low-detail.
Refinement: REPLACE vs ADD. REPLACE — classic HLOD: when children load, the parent hides. That's how buildings work (low-poly building gets replaced by high-poly). ADD — children stack on top of the parent. That's how point clouds work (LiDAR delta-detail) and photogrammetry (refinement via an additional texture layer).
Geometric error. This scalar is the estimate in meters of how much rendering this tile differs from ground truth. The root tile might have an error of 500 m (city shape visible, individual buildings not). A tree leaf — 0.1 m (precise facades). The client uses error to compute SSE and decide LOD.
The mermaid diagram above shows a tileset tree: root with region bounding volume → two regional children → leaf tiles with glb content.

3D Tiles vs CityGML vs CityJSON vs glTF
A frequent mix-up. These four formats live in different layers of the 3D mapping stack:
- CityGML — OGC semantic data exchange format. An XML schema for municipal/cadastral exchange of 3D city models with rich semantics (RoofSurface, WallSurface, building parts, LoD 0-3). For exchange and storage, not rendering.
- CityJSON — compact JSON encoding of the same CityGML model (6× smaller than XML). Also for exchange, more web-friendly.
- glTF/GLB — generic 3D model format for rendering a single asset (one building, one car, one scene). Khronos standard. No hierarchy or LOD streaming.
- 3D Tiles — streaming format for rendering large 3D scenes. tileset.json hierarchy + bounding volumes + LOD + holds glTF tiles. For visualization, not exchange.
A typical pipeline: a municipal city model is stored as CityGML (archive and cadastral exchange) → converted to 3D Tiles (web streaming through CesiumJS) → individual buildings exported to glTF (for use in Unity/Blender). On osm2cdr.ru we support all four — the choice depends on use case.
Strengths and weaknesses
Strengths. Streaming large datasets through plain HTTP — no scene size limit (Google Earth 3D stores terabytes in 3D Tiles). HLOD with automatic LOD-driven screen-space error — the user sees the right detail for current zoom without manual switching. The bounding volume tree provides fast frustum culling — only visible tiles render. Since 3D Tiles 1.1, native glTF 2.0 content with support for any glTF extension (PBR materials, animations, draco compression). OGC standard since September 2023 — international recognition. Supported by CesiumJS, deck.gl, MapboxGL JS (limited), Unity (Cesium for Unity), Unreal (Cesium for Unreal), iTwin.js.
Weaknesses. Complex authoring pipeline — needs a LOD generator (3d-tiles-tools, py3dtiles, FME) and spatial chunker. Can't be opened in a regular 3D viewer without a 3D-Tiles-aware library (Blender won't load tileset.json as a scene). Data duplication in the LOD tree — a full tileset is 30-50% larger than the source originals because of downsampled versions. Version mismatch 1.0 (b3dm) vs 1.1 (glTF native) — old viewers may not read 1.1, new ones may not understand legacy b3dm. Semantics is poorer than CityGML/CityJSON — for municipal use the CityGML → 3D Tiles workflow is better.
Where it's used
Google Earth 3D. Internal format for 3D cities in Google Earth — buildings, terrain, photogrammetry stitched as 3D Tiles tilesets. Served through Google Photorealistic 3D Tiles API (paid, since 2023) — developers can integrate the same photogrammetry dataset into their Cesium / Unreal apps.
Cesium ion. Cloud hosting service from Cesium GS. Accepts CityGML / OBJ / FBX / LAS on upload, converts to 3D Tiles, serves through CDN. One of the main sources of 3D cities for digital-twin developers.
ArcGIS Scene Service. ESRI has supported 3D Tiles in ArcGIS Online since 2020 as an alternative to its proprietary I3S format. Pro lifecycle: create a scene in ArcGIS Pro → publish to ArcGIS Online as 3D Tiles or I3S → consume in ArcGIS Maps SDK / CesiumJS.
Drone photogrammetry pipelines. RealityCapture, Pix4D, Bentley ContextCapture — all export 3D Tiles as one of the output formats for drone meshes. Surveyors fly an area, generate a mesh, export to 3D Tiles, host on Cesium ion / R2, the client views in CesiumJS.
LiDAR streaming. US Geological Survey 3DEP, Open Topography, ASPRS host LiDAR point clouds as 3D Tiles pnts content. Several terabytes per state — streamable through the web without download.
Urban digital twins. Helsinki, Singapore, Zurich, San Francisco published their city models as 3D Tiles for public access — city planners, developers, researchers can analyze the urban fabric right in the browser.
Software for 3D Tiles
CesiumJS. Free, open-source (Apache 2.0). The reference WebGL viewer for 3D Tiles. JavaScript library, integration through Cesium.Cesium3DTileset API. Supports both 1.0 (b3dm) and 1.1 (glTF native).
Cesium ion. Cloud paid service from Cesium GS for tileset hosting and conversion. Tiers: Community (free, 5 GB), Commercial ($300/mo, 50 GB). OBJ/FBX/CityGML/LAS → 3D Tiles conversion in the cloud.
3d-tiles-tools. Free CLI from Cesium GS — a Node.js package for tileset generation and validation. Converts glb files + bbox metadata → tileset.json hierarchy.
py3dtiles. Free Python package (Oslandia) — open-source alternative for 3D Tiles generation from point clouds (LAS/LAZ) and meshes (OBJ/PLY).
deck.gl. Free (Uber/Vis.gl). A WebGL framework with Tile3DLayer support — a CesiumJS alternative for React app integration.
iTwin.js. Free/paid (Bentley). 3D Tiles support in the iTwin.js viewer for federated BIM models.
Cesium for Unity / Unreal. Free plugins — load 3D Tiles tilesets as a world in Unity or Unreal Engine for game-engine visualization of urban scenes.
FME (Safe Software). Paid. ETL platform with enterprise-level CityGML → 3D Tiles conversion.

Pipeline in OSM2CDR
Our tiles3d_exporter.py is a multi-step pipeline for generating a full 3D Tiles tileset from OSM data:
Step 1: Fetch OSM buildings. PostGIS query on planet_osm_polygon by bbox with filter building IS NOT NULL. Extracts footprint geometry, tags building:levels / height / building:height for extrusion height computation.
Step 2: Building3D extrude. Building3DExporter takes the 2D building polygons and extrudes them vertically by height (floors × 3 m, or the explicit height tag). Optionally adds a roof — flat by default, hipped/gabled for tagged ones. Output is a 3D mesh with a triangle list per building.
Step 3: Spatial chunking. The bbox is split into a quadtree with an adaptive threshold — coarse tiles for sparse areas, fine tiles for the center. Each tile gets the building meshes that fall inside its region.
Step 4: glTF 2.0 generation. For every spatial chunk a .glb (binary glTF) is generated through pygltflib. Buildings pack into one mesh with per-feature batchId through the EXT_mesh_features extension. Per-feature metadata (OSM ID, building type, floors) — through EXT_structural_metadata.
Step 5: tileset.json assembly. A root tileset.json is generated with root tile and quadtree children. Each tile gets boundingVolume.region in WGS84, geometricError (root: 500m → leaves: 5m), refine: "REPLACE", content.uri pointing to the matching .glb.
Step 6: ZIP packaging. All files pack into a single .zip — tileset.json + a tiles/ directory with glb files. The user unpacks to static hosting (CloudFlare R2 / S3 / GitHub Pages) and wires it into CesiumJS with viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: 'https://.../tileset.json' })).
Output 3D Tiles tileset for a ~1×1 km bbox (typical ~5000 buildings) is 5-15 MB fully expanded. With draco compression (option in advanced settings) — 2-5 MB. Streamable through any HTTP server with no backend.
FAQ
Version 1.0 or 1.1 — which is generated? OSM2CDR generates 3D Tiles 1.1 (glTF native) — the current OGC standard from September 2023. Compatible with CesiumJS 1.107+, deck.gl 9+. For legacy viewers (Cesium 1.99-, proprietary BIM tools) there's a fallback option to b3dm — conversion through 3d-tiles-tools downgrade.
How does 3D Tiles differ from glTF? glTF is a single 3D asset (one model, one scene). The client loads it in full. 3D Tiles is a hierarchical tree of many tiles, each of which may be glTF. A tileset streams in pieces with LOD — the client pulls only visible tiles and only at the needed detail. glTF for a single model, 3D Tiles for a whole city or photogrammetry region.
Can 3D Tiles be viewed locally without a server? Technically yes if you open an HTML with CesiumJS through python -m http.server (or any static server) — file:// URLs fail due to CORS. In production it's usually CDN or S3 / R2 hosting. Cesium ion has a free tier of 5 GB for public datasets.
How is 3D Tiles related to BIM? BIM models in the IFC format can be converted to 3D Tiles for federated viewing in the browser without a proprietary BIM Viewer. Pipeline: IFC → OBJ/glTF (through IfcConvert or Blender BlenderBIM) → 3D Tiles (through 3d-tiles-tools or Cesium ion). IFC semantic attributes are preserved through EXT_structural_metadata.
Is photogrammetry streaming supported in OSM2CDR? No — our export comes only from OSM data — buildings are extruded from 2D footprints with approximate height. Photogrammetry meshes require drone scan or mobile mapping (LiDAR) input, which OSM doesn't contain. For photogrammetry input use RealityCapture / Pix4D / Bentley ContextCapture with 3D Tiles output.
Related
- CityJSON — compact JSON encoding of CityGML 3.0
- CityGML — OGC standard for 3D city models
- glTF — Khronos 3D model format for the web
- IFC — buildingSMART standard for BIM
- Which 3D format to pick for OSM buildings
Sources
- 3D Tiles Specification 1.1 — docs.ogc.org/cs/22-025r4/22-025r4.html
- 3D Tiles 1.0 Community Standard — github.com/CesiumGS/3d-tiles
- CesiumJS — cesium.com/platform/cesiumjs
- Cesium ion — cesium.com/platform/cesium-ion
- 3d-tiles-tools — github.com/CesiumGS/3d-tiles-tools
- py3dtiles (Oslandia) — gitlab.com/Oslandia/py3dtiles