f2d71da8e1d78c81bec0bd14e6c710244cf377dd
Replaced the memory-intensive full image read of per-tile orthophotos with a windowed read from the global Ortho VRT. This fixes memory crashes and ensures correct texture coverage for buildings that cross tile boundaries.
GeoData Toolkit
This repository converts DGM1 elevation tiles into Unity-ready 16-bit PNG heightmaps and a placement manifest. It relies on GDAL for mosaicking, resampling, and scaling to UInt16 ranges Unity expects.
Prerequisites
uvinstalled. Use Python 3.10–3.12 for now (triangle2fromcjio[export]has no CPython 3.13 wheels).- Optional: Java 17+ if you want to experiment with the bundled
citygml-toolsutilities (not needed for heightmaps/orthophotos).
Environment setup (uv)
- Install deps (creates
.venvif missing):uv sync. You can skip manual activation by prefixing commands withuv run ...; if you prefer activation, runuv venv && source .venv/bin/activate. uv run <cmd>executes with the project environment (e.g.,uv run python geodata_to_unity.py --setup). Use--directoryto target another path if needed;--offlinedisables network fetches.- If wheels fail to resolve, ensure system GDAL is present (e.g.,
brew install gdalorapt-get install gdal-bin libgdal-dev), then rerunuv sync. - Create the default directory tree and config:
uv run python geodata_to_unity.py --setup(orbash scripts/setup_dirs.shfor directories only).
Repository Layout
raw/— working inputs (not versioned):raw/dgm1/,raw/dop20/jp2/,raw/citygml/lod1/,raw/citygml/lod2/.archive/— offline storage for untouched downloads (e.g., zipped DOP/CityGML tiles, dop20 filelist).work/— intermediates such asdgm.vrtand_tmp.tiffiles; safe to delete/regenerate.export_unity/height_png16/— final 16-bit PNG heightmaps for Unity import.export_unity/tile_index.csv— manifest mapping tile IDs to world bounds and scaling ranges (global_min/global_maxplus per-tiletile_min/tile_max), plustile_key; built during heightmap export and required by orthophotos.export_unity/ortho_jpg/— cropped orthophoto tiles aligned to the terrain grid (JPEG + worldfiles).geodata_to_unity.py— main CLI (usesgeodata_pipeline/library modules).scripts/— helpers to create the directory tree and fetch DOP20 inputs.geodata_config.toml— generated config (seegeodata_config.example.tomlfor defaults).AGENTS.md— contributor guide.
Quick Start
- Activate the uv venv (
source .venv/bin/activate) or prefix commands withuv run. - Initialize config + directories:
uv run python geodata_to_unity.py --setup. - Export assets (builds VRTs automatically if missing):
uv run python geodata_to_unity.py --export all # heightmaps only: uv run python geodata_to_unity.py --export heightmap # textures only: uv run python geodata_to_unity.py --export textures # buildings: uv run python geodata_to_unity.py --export buildings # trees (CSV+GLB): uv run python geodata_to_unity.py --export trees - Import the PNGs into Unity Terrains using
tile_index.csvfor placement and height scaling (0–65535, per-tile by default).
How the export works
- Heightmaps: the pipeline builds
work/dgm.vrtfrom allraw/dgm1/*.tif, computes a global min/max once (legacy fallback), and warps each tile footprint toheightmap.out_reswithsrcNodata=-9999. Per-tile min/max are computed from the warped tile and used to scale PNGs to[0, 65535]by default (heightmap.use_tile_minmax=falsekeeps global scaling).export_unity/tile_index.csvrecordsglobal_min/global_max,tile_min/tile_max, andtile_key = f"{floor((xmin + overlap_x) / tile_size_x)}_{floor((ymin + overlap_y) / tile_size_y)}"(defaults:tile_size_x=1000.0,tile_size_y=1000.0,overlap_x=0.5,overlap_y=0.5in[tile_key]). - Orthophotos:
work/dop.vrtis built fromraw/dop20/jp2/*.jp2; the manifest drives the cropping bounds. JPEG tiles are written toexport_unity/ortho_jpg/with matching.jgwworldfiles. If the manifest is missing, the orthophoto export aborts—run the heightmap export first or use--export all. - Archives:
--build-from-archiveexpands every*.zipunderarchive/*into the matchingraw/*directories and copiesarchive/dop20/filelist.txtnext toraw/dop20/for the downloader. - Cleanup: temporary
_tmp.tifand GDAL aux XML files underwork/andraw/dgm1/are removed at the end of the heightmap export; avoid storing non-GDAL metadata in those folders.
Key Commands
- Refresh VRT:
gdalbuildvrt work/dgm.vrt raw/dgm1/*.tif - Run export pipeline:
uv run python geodata_to_unity.py --export all - Inspect an output tile:
gdalinfo export_unity/height_png16/<tile>.png | head - Override config paths: use
--config <path>,--raw-dgm1-path <dir>,--raw-dop20-path <dir>. - Build raws from archives:
uv run python geodata_to_unity.py --build-from-archive --export all(unzipsarchive/*; dop20 filelist stays inarchive/dop20/for the downloader). - Rebuild VRTs after moving data: add
--force-vrt.
Workflow Notes
- Heightmaps normalize per tile using
tile_min/tile_maxby default; setheightmap.use_tile_minmax=falseto restore global scaling across tiles. Adjustheightmap.out_resorheightmap.resampleingeodata_config.tomlif your AOI or target resolution changes. tile_keyconfig controls the tile grouping key in the manifest; defaults aretile_size_x=1000.0,tile_size_y=1000.0,overlap_x=0.5,overlap_y=0.5withenabled=true._tmp.tiffiles inwork/are transient; you can deletework/to force a clean rebuild.- Keep file names stable to avoid churn in Unity scenes; re-exports overwrite in place.
- Large raw datasets are intentionally excluded from version control—document download sources or scripts instead of committing data.
- Additional inputs: download helper lives in
scripts/dlscript_dop20.shand pulls JP2/J2W/XML orthophotos listed inarchive/dop20/filelist.txt(one URL per line);archive/can hold zipped 3D building tiles for future use. - Handoff to Unity: copy/sync
export_unity/height_png16/andexport_unity/tile_index.csvintoDTrierFlood/Assets/GeoData/before running the Unity-side importer. Keepheightmap.out_resaligned with the importer’s expected resolution (currently 1025).
Orthophotos (textures)
- Ensure DOP assets are present in
raw/dop20/jp2/,raw/dop20/j2w/, andraw/dop20/meta/; usescripts/dlscript_dop20.shto fetch JP2/J2W/XML entries listed inarchive/dop20/filelist.txt(one URL per line). - From
GeoData/, run:This buildsuv run python geodata_to_unity.py --export textureswork/dop.vrtif missing and writesexport_unity/ortho_jpg/<tile>.jpg+.jgwaligned totile_index.csv.- If you see
Computed -srcwin ... falls partially outside source raster extentwarnings, the DOP coverage is slightly smaller than the tile footprint; edge pixels will be filled with NoData/zeros. Add adjacent JP2s or shrink the requested window if you need to avoid the warning. - The download script relies on a Linux/OpenSSL toolchain with system CA bundle at
/etc/ssl/certs/ca-certificates.crt; it builds a trust chain by fetching the geobasis intermediate. macOS/Windows users should either provide a combined CA viaCURL_CA_BUNDLEor download with a browser/wget and place files manually. - Place companion
.j2wand.xmlfiles underraw/dop20/j2w/andraw/dop20/meta/if available; they are not required for the VRT but help provenance.
- If you see
Downloads (raw data)
- Run:
uv run python geodata_to_unity.py --download(usesgeodata_download.toml). - Shows a progress bar while downloading and exits cleanly on Ctrl+C (exit code 130).
Buildings (automated exporter)
- Run:
uv run python geodata_to_unity.py --export buildings - What it does per tile:
- Converts LoD2 CityGML → CityJSON (citygml-tools), triangulates with cjio, rebases to tile-local XY using
tile_index.csv. - Merges all buildings into one GLB (1 mesh with roof/wall primitives), decimates to the configured triangle budget.
- Roofs: planar UVs from tile-local XY, embedded per-tile DOP20 orthophoto as base color (unlit by default).
- Walls: vertex colors sampled from the ortho as a fallback (neutral otherwise).
- Coordinates: glTF-friendly (x=east, y=height, z=-north) so glTFast instantiates one GameObject with two submeshes.
- Converts LoD2 CityGML → CityJSON (citygml-tools), triangulates with cjio, rebases to tile-local XY using
- Requirements: LoD2 GMLs under
raw/citygml/lod2/, per-tile orthos inexport_unity/ortho_jpg/, tools on PATH (tools/citygml-tools-2.4.0/citygml-tools,cjioor override viaCJIOenv). - Open items: richer wall coloring from BDOM/LPO facades, better simplification, footprint-aware ground snapping beyond the current clamp-to-ground.
Troubleshooting
- Empty raw directories cause VRT creation to fail fast (
No sources available to build VRT); populate inputs or adjust--raw-*overrides. - If you moved raw data or deleted
work/, add--force-vrtto rebuild VRTs before exporting. - Orthophoto export warnings like
Computed -srcwin ... falls partially outside source raster extentindicate coverage gaps; add neighboring JP2s or accept the NoData edge fill. - If GDAL Python bindings are missing, install system GDAL first and re-run
uv syncsoosgeoimports succeed.
Description
Languages
Python
75.3%
C#
20.4%
Shell
3.4%
Batchfile
0.9%