OSM 3D Model
One-click OpenStreetMap to interactive Three.js 3D city viewer • v1.2.0
1. Overview
OSM 3D Model is a single-click QGIS-to-browser pipeline that downloads live OpenStreetMap data for a user-defined study area and opens an interactive Three.js 3D city viewer. The plugin handles the entire data pipeline—Overpass API download with multi-mirror fallback and 7-day disk cache, OSM tag parsing into 11 memory layers, GeoJSON export with a manifest, and a local HTTP server that launches the browser-based PlanX 3D City engine. The viewer renders procedural buildings with roof styles, roads with lane markings and animated traffic, sidewalks with pedestrians, trees, street furniture, water features, and optional DEM terrain and basemap underlay.
2. Theoretical Foundations
2.1 OSM Data Quality for 3D Urban Modelling
Goetz (2013) demonstrated the feasibility of generating CityGML-compliant 3D city models from OpenStreetMap data, establishing the methodological foundation this plugin follows. The approach uses OSM's two-dimensional geometry (building footprints, road centrelines, green-space polygons) enriched with semantic tags and optional height attributes, then procedurally extrudes the third dimension. Fan et al. (2014) validated building footprint completeness and positional accuracy in OSM, finding >80% completeness in well-mapped urban areas. Biljecki et al. (2017) demonstrated that LOD1 building models generated from OSM without external elevation data can achieve useful accuracy when building height or floor-count attributes are present, directly supporting the plugin's three-tier height derivation strategy.
2.2 Procedural Content Generation in Urban Contexts
The web viewer follows Parish and Muller's (2001) procedural city generation paradigm, extended from their CityEngine system. Buildings are generated from footprint polygons using parametric roof styles (flat, pyramid, gable, hip, shed). Roads are extruded from linestrings with lane marking shaders. Trees are instanced with multiple stylistic variants. Street furniture (benches, lamps, bins) is aligned to road edges. The deterministic PRNG for tree placement ensures reproducibility using a seeded LCG based on polygon coordinates. This approach produces visually rich results without requiring detailed 3D model libraries.
2.3 Web-Based 3D GIS Visualisation
The viewer uses WebGL via Three.js for browser-based rendering, following the trend identified by Resch et al. (2014) toward web-based 3D GIS platforms. The architecture separates data preparation (Python/QGIS) from visualisation (JavaScript/WebGL), communicating through a local HTTP server with GeoJSON as the interchange format. This separation enables offline operation while maintaining browser-based interactivity and cross-platform compatibility.
3. Data Pipeline
Ten-Step Export Pipeline
- Area resolution: User selects canvas extent or polygon features. Returns (QgsGeometry, QgsCoordinateReferenceSystem).
- Study area preparation: Reproject to WGS84 for Overpass, UTM for geometry.
compute_study_area()applies shape (circle/rounded/extent/polygon) and area clamp (1–300 ha, default 150 ha). Circle uses pole-of-inaccessibility algorithm. Creates model base by buffering 5 m outward. - OSM download:
QgsTaskbackground thread fetches from Overpass API with multi-mirror fallback. - Parse and build: Iterates every OSM element, clips to study boundary, builds 11 in-memory vector layers with computed attributes.
- GeoJSON export: Writes each layer to GeoJSON via
QgsVectorFileWriter.writeAsVectorFormatV3(). - Atomic publish: Staging directory →
web/data/yerlesim/with backup on failure. Every GeoJSON validated as valid FeatureCollection. - Optional DEM export:
gdal:warpreproject, bounded to ~512 px max dimension, output asweb/data/dem/mydem.tif. - Optional basemap export:
QgsMapRendererCustomPainterJobat max 2048 px, transparent PNG, output asweb/data/basemap/basemap.png. - Manifest: Writes
planx_manifest.jsonwith schema, field mappings, theme colours, and viewer defaults. - Viewer launch: HTTP server starts on a free port (8120–8139), browser opens
http://127.0.0.1:{port}/src/.
4. Study Area Definition
Area Sources and Boundary Shapes
Two area sources: Current map extent (canvas) or Selected polygon features (active layer, dissolved via unaryUnion()). Four boundary shapes: Circle (pole of inaccessibility algorithm, largest inscribed circle, clamped to max area, default), Rounded rectangle (corners at ~16% of short side via double-buffer technique), Extent (plain bounding box), and Polygon (exact selected geometry). Area is auto-reprojected to local UTM zone: \(\mathrm{zone} = \lfloor(\lambda + 180)/6\rfloor + 1\), EPSG = 32600 + zone (north) or 32700 + zone (south). Clamped to a configurable maximum (1–300 ha, default 150 ha). Study area inherits a 5 m presentation platform extending beyond the clip boundary with rounded corners.
5. OSM Data Download
Overpass API Pipeline with Multi-Mirror and Cache
Queries Overpass API for buildings, highways (including cycleway deduplication), waterways, water areas, green spaces (parks, forests, pitches, cemeteries, parking lots, pedestrian squares), trees, bus stops, benches, street lamps, and waste baskets within the WGS84 bounding box. Uses out body geom; suffix for full geometry with 60-second timeout.
Multi-mirror: Three endpoints tried in order: overpass-api.de, overpass.kumi.systems, overpass.private.coffee. HTTP 429 triggers next mirror. First valid non-empty JSON wins.
Cache: SHA-256 of query string, first 40 chars, stored in %TEMP%/osm_3d_model_cache/. TTL: 7 days (604800 s). Cache validation checks payload structure for corrupt files.
6. Data Layers (11)
Exported GeoJSON Layers
| Layer | Geometry | Key Attributes |
|---|---|---|
| OSM Buildings | MultiPolygon | osm_id, building, building_levels, height, roof_shape, roof_height, name |
| OSM Roads | MultiLineString | osm_id, highway, width, name |
| OSM Bike lanes | MultiLineString | osm_id, highway, width, name, road_width, side |
| OSM Greens | MultiPolygon | osm_id, leisure, landuse, natural, amenity, highway, place, name |
| OSM Waterlines | MultiLineString | osm_id, waterway, width, name |
| OSM Water areas | MultiPolygon | osm_id, natural, waterway, landuse, name |
| OSM Trees | Point | osm_id, natural, height |
| OSM Bus stops | Point | osm_id, highway, name |
| OSM Benches | Point | osm_id, amenity |
| OSM Street lights | Point | osm_id, highway |
| OSM Trash bins | Point | osm_id, amenity |
Export uses QgsVectorFileWriter.writeAsVectorFormatV3() with GeoJSON driver and UTF-8. Atomic publish: staging directory → target via Path.replace() with backup on failure. Each GeoJSON validated as a non-empty FeatureCollection.
7. Building Height Logic
Three-Tier Fallback with 57 Type-Specific Defaults
- Parse
building:levelsorlevelstag, rounded to integer, clamped to ≥1. - If absent: parse
heighttag (supports m, cm, km, ft, feet, inch units), divide by 3.0, round, clamp to ≥1. - Function-based default from 57-entry dictionary: apartments=4, residential=4, house/detached/terrace=2, bungalow=1, office=5, retail/supermarket/kiosk=1, commercial=3, industrial=1, school=3, university/college=4, hospital=5, church/mosque/temple/synagogue/chapel=1 (cathedral=2), warehouse/hangar/manufacture=1, garage/shed/hut/roof/carport=1, unknown=3.
- Add
roof:levelsif present. Final: max(1, base + roof_levels).
Additional columns: height (OSM height tag, float metres), roof_height (OSM roof:height tag), footprint_m2 (computed), gfa_m2 (computed = footprint × building_levels).
8. Three.js Viewer
Scene Composition and Rendering
The viewer (web/src/app.js, ~9500+ lines) is a single-page Three.js application. Core rendering: WebGLRenderer with antialiasing, PCFSoftShadowMap shadows, ACES filmic tone mapping (exposure 1.32). Post-processing: EffectComposer chain: RenderPass → SSAOPass (optional) → UnrealBloomPass (optional, strength 0.3, radius 0.4, threshold 0.85) → OutputPass. CSS2DRenderer for 2D labels overlaid on 3D.
Lighting: DirectionalLight (intensity 1.38, shadow map 2048x2048, position 200,450,150) + AmbientLight (intensity 1.18). Procedural sky dome with ShaderMaterial (horizon #f6fbff to zenith #9ed8ff), star field (pseudo-random hash) at night.
Camera: PerspectiveCamera (45° FOV, near 1, far 10000). OrbitControls (damping 0.05, max polar angle ~90°). Also supports PointerLockControls for first-person walk mode (WASD, Shift sprint, C crouch). Fit algorithm: distance = max(220, min(maxDim × 2.4, 320, 1800)).
Boot sequence: loadManifest → applyManifestDefaults → loadGeoJson (all layers) → loadProjectDem → loadBaseMapTexture → buildTerrain → buildIslandLayer → building/road/sidewalk/waterline/fences/trees/furniture/traffic layers all rebuilt based on settings → loading screen fades out.
9. Viewer Panel System
Eight Dockable Panels with Toolbar Tray
| Panel | Controls |
|---|---|
| Dashboard | Scene metrics (building count, green area, avg floors, population, dwellings, vehicles), project metadata, area statistics |
| Layers | Per-category visibility: buildings, roads, bike lanes, waterways, greens, trees, sidewalks, furniture, cars, cyclists, pedestrians, outside-ROI terrain |
| Style | Block texture/transparency, road colour/texture, ground texture, terrain tile size, asset theme, tree render mode/variant/height, building mode/facade scale/floor height/roof shape/height/texture, procedural rules (ledges, storefronts, setback, ledge projection), per-category block styles |
| Scene & Sun | Time-of-day slider (6:00–22:00), solar animation, weather presets, fog density, SSAO/Bloom toggles, traffic/pedestrian density, model base controls, camera bookmarks |
| Basemap & Texture | Show basemap toggle, opacity, blend mode (Normal/Multiply/Screen/Add/Difference), shadow catching, drape height, brightness/contrast/saturation/tint |
| Model Studio | Upload custom GLB models per furniture category, library management, tree model pool (random selection), per-category transforms (position/scale/rotation) |
| Export Studio | PNG/JPEG/WebP/PDF/SVG/HTML stills, WebM/MP4 screen recording (30/60 fps, standard/high/ultra bitrate), clipboard copy |
| Walk Mode | First-person WASD navigation at pedestrian eye height, Shift sprint, C crouch |
All settings are persisted to localStorage under the key planx_3d_city_settings (schema v13) with migration logic. Scene rebuild tokens abort stale rebuilds when settings change rapidly.
10. Color Themes (11)
Coordinated Palettes for Island, Terrain, Roads, Parks, Water, Roofs
| Theme | Character | Island Base |
|---|---|---|
| Editorial Paper | Warm ivory; default | #e6dfd3 |
| Plugin Tones | Salmon and grey | #d4c5c0 |
| Tinted Gray Teal | Muted cool grey-green | #c8d6d2 |
| Teal & Salmon | Warm-cool contrast | #c8c0b8 |
| Light Purple & Black | Elegant purple accents | #d8d5e0 |
| Warm Sand & Slate | Natural earth tones | #ddd5c8 |
| Anime (Anime Cel) | Bright cel-shaded pastels | #9fb6c4 |
| Cartoon | Bold primary colours | #c4c8c0 |
| Pixar | Warm creams and oranges | #e8dcc8 |
| Futuristic City | Dark neon, cyan/violet glass | #121420 |
| Classic Era | Vintage sepia, terracotta roofs | #d4c8b0 |
QGIS parallel styling: qgis_styling.py applies a categorised symbol renderer to buildings (6 function categories), roads (8 hierarchy levels with metric width expressions), and greens (8 categories including water, parking, pedestrian squares). Point layers receive single-symbol renderers. Theme palette is mirrored in both the QGIS project layers and the viewer manifest, ensuring visual consistency across environments.
11. Procedural Buildings and Facades
Canvas-Drawn Textures and Parametric Roofs
Facade textures: Canvas-drawn at runtime using FACADE_RECIPES with a storey-based window grid. Ground floor: shopfronts for Commercial/Mixed-Use (light blue glazing), entrance doors for Residential/Civic. Upper floors: coloured window rectangles, ~48% randomly lit (warm gold, amber/orange, cool blue, soft teal). A separate emissive map texture enables night glow when the day/night cycle enters night mode. 17 procedural roof texture variants (tile patterns, standing seam, shingle, solar, ceramic).
Roof geometry: Flat (with penthouse, HVAC, helipad/solar panels), Pyramid (concave-footprint-aware), Hip (ridge line at mid-height), Gable (ridge along OBB long axis), Shed (single slope).
Building setback: offsetRing() performs iterative vertex offset with hole detection, producing the footprint available for building generation. perBuildingColorVariation adds HSL lightness variation seeded by OSM ID for visual distinction.
Procedural ground textures: Asphalt, water, island block, and fence materials all generated via canvas drawing routines with configurable colours from the active theme.
12. Roads and Traffic
Road Surfaces, Sidewalks, Bike Lanes, and Animated Traffic
Roads: buildRoadLayer() constructs ribbon meshes along OSM way linestrings, extruded with configurable width per road class (motorway, trunk, primary, secondary, tertiary, residential, service, footway, cycleway). Lane markings: procedural dashed centre/side lines.
Sidewalks: Kerbed sidewalk ribbons on both sides, width scaled by road class. Placed via offset from road centrelines. Streetlights and trees alternate along sidewalks.
Bike lanes: Green ribbon strips offset to road-relative sides, using the OSM cycleway side tag when available.
Traffic: Instanced meshes for cars, vans, buses, and trucks with wheels and lights. Spawned on car-capable roads (excludes footways, cycleways). Frame-rate independent motion controlled by settings.trafficSpeed. Pedestrians keep to sidewalks with sidewalk-relative positioning. Cyclists ride on bike lanes when present. Night mode activates vehicle headlights/taillights and streetlight bulbs.
13. Terrain and Basemap
Optional DEM and Raster Underlay
DEM: Warped via gdal:warpreproject to the model base extent, bounded to ~512 px maximum dimension to keep file size manageable. The viewer loads GeoTIFF via the geotiff.js library and constructs a height-mapped terrain mesh. Terrain resolution is configurable.
Basemap: Rendered via QgsMapRendererCustomPainterJob at max 2048 px to transparent PNG. In the viewer, it appears as a flat underlay beneath the city with configurable opacity, blend mode (Normal/Multiply/Screen/Add/Difference), brightness, contrast, saturation, and tint. Shadow catching can be enabled to project building shadows onto the basemap surface. Drape height controls the vertical offset between basemap and city features.
14. Export Studio
Stills, Video Recording, and Clipboard
Still formats: PNG, JPEG (quality slider), WebP, PDF (raw PDF 1.4 from JPEG with proper cross-reference table), SVG (embeds JPEG as href), HTML (self-contained page). Size options: viewport, Full HD (1920x1080), QHD (2560x1440), 4K (3840x2160), custom. Video recording: WebM or MP4, 30 or 60 fps, standard/high/ultra bitrate. Filename sanitisation and timestamped generation. Clipboard copy via navigator.clipboard.write().
15. Caching and HTTP Server
Atomic Data Publish with Security Headers
Cache: SHA-256 of Overpass query (first 40 chars), stored as JSON in %TEMP%/osm_3d_model_cache/. TTL: 7 days. On-hit validation: corrupt files are discarded and re-fetched. Cache management UI exposes clear-cache button with count and byte-freed report.
HTTP server: ThreadingTCPServer on 127.0.0.1, ports 8120–8139, daemon threads. QuietHandler adds security headers: Cache-Control: no-store, Cross-Origin-Resource-Policy: same-origin, Referrer-Policy: no-referrer, X-Content-Type-Options: nosniff, X-Frame-Options: DENY. Custom MIME types: application/json (.geojson), image/tiff (.tif), image/webp (.webp), application/javascript (.js).
16. Parameters and Controls
| Parameter | Type | Range | Default |
|---|---|---|---|
| Study area source | Radio | Map view / Selection | Map view |
| Boundary shape | Combo | Circle / Rounded / Extent / Polygon | Circle |
| Max study area | QDoubleSpinBox | 1–300 ha | 150 ha |
| Map & web theme | Combo | 11 options | Editorial Paper |
| DEM (optional) | QgsMapLayerComboBox | Raster layers | None |
| Basemap (optional) | QgsMapLayerComboBox | Any layer | None |
| Open viewer automatically | QCheckBox | On / Off | On |
| Clear OSM cache | QPushButton | — | Reports files + bytes freed |
17. Workflow Guide
- Pan and zoom the QGIS canvas to the desired study area, or select polygon features.
- Click the OSM 3D Model toolbar icon to open the dialog.
- Optionally click Add OSM basemap to the map for a reference tile layer.
- Choose area source, boundary shape, and max area. The live area readout shows estimated hectares.
- Select a theme from the dropdown (affects both QGIS layer styling and 3D viewer colours).
- Optionally expand Advanced to add a DEM raster or basemap layer, or clear the OSM cache.
- Click Create OSM layers & export 3D viewer. The plugin downloads, processes, exports, and opens the viewer.
- In the viewer, use the toolbar to open panels. Switch themes live via the Style dock without re-exporting.
- The export result is also added as a styled QGIS layer group ("3D OSM Model") for inspection and analysis.
- Use Export Studio for stills, video, or clipboard output. Use Walk Mode for first-person exploration.
18. Technical Notes
- CRS handling: Study area centroid → local UTM EPSG code. All geometry processing uses metric coordinates.
- Multipolygon assembly: OSM relations stitched into multipolygons with outer/inner ring logic for building courtyards.
- Tree scattering: Deterministic LCG PRNG seeded from polygon coordinates + area + kind code → identical on re-runs.
- Server security: 127.0.0.1 bind only. Same-origin CORS, no-store cache, nosniff, DENY framing, no-referrer.
- Atomic publish: Staging directory → target via
Path.replace()with backup on failure. - Viewer: ~9500-line Three.js app. ES module imports. WebGLRenderer with shadow maps + EffectComposer (SSAO/Bloom). Settings persist in IndexedDB (v13 schema). Scene rebuild tokens abort stale rebuilds.
- QGIS compatibility: 3.28–4.99. Pure qgis.core/gui/PyQt. No external Python dependencies.
19. Literature
- Haklay, M. & Weber, P. (2008). OpenStreetMap: User-generated street maps. IEEE Pervasive Computing, 7(4), 12–18. DOI: 10.1109/MPRV.2008.80
- Biljecki, F., Ledoux, H., & Stoter, J. (2017). Generating 3D city models without elevation data. Computers, Environment and Urban Systems, 64, 1–18. DOI: 10.1016/j.compenvurbsys.2017.01.001
- Goetz, M. (2013). Towards generating highly detailed 3D CityGML models from OpenStreetMap. International Journal of Geographical Information Science, 27(5), 845–865. DOI: 10.1080/13658816.2012.721552
- Kolbe, T. H. (2009). Representing and exchanging 3D city models with CityGML. In J. Lee & S. Zlatanova (Eds.), 3D Geo-Information Sciences (pp. 15–31). Springer. DOI: 10.1007/978-3-540-87395-2_2
- Parish, Y. I. H. & Muller, P. (2001). Procedural modeling of cities. Proceedings of SIGGRAPH 2001, 301–308. DOI: 10.1145/383259.383292
- Fan, H., Zipf, A., Fu, Q., & Neis, P. (2014). Quality assessment for building footprints data on OpenStreetMap. International Journal of Geographical Information Science, 28(4), 700–719. DOI: 10.1080/13658816.2013.867495
- Resch, B., Wohlfahrt, R., & Wosniok, C. (2014). Web-based 4D visualization of marine geo-data using WebGL. Cartography and Geographic Information Science, 41(3), 235–247. DOI: 10.1080/15230406.2014.901001
- Goodchild, M. F. (2007). Citizens as sensors: The world of volunteered geography. GeoJournal, 69(4), 211–221. DOI: 10.1007/s10708-007-9111-y
- Dirksen, C. (2014). Three.js Essentials. Packt Publishing.
- Muller, P., Wonka, P., Haegler, S., Ulmer, A., & Van Gool, L. (2006). Procedural modeling of buildings. ACM Transactions on Graphics, 25(3), 614–623. DOI: 10.1145/1141911.1141931