A GDExtension for Godot Engine 4.x that enables loading 3D city models (CityGML) provided by Japan's Ministry of Land, Infrastructure, Transport and Tourism (MLIT).
- Load CityGML files
- Generate and display 3D meshes
- LOD (Level of Detail) selection
- Coordinate conversion (Geographic ↔ Local coordinates)
- Texture loading with caching
- PBR material support (Metallic/Roughness/Emission)
- Smooth shading with auto-generated normals
- Attribute information access (GML ID, CityObjectType, attributes)
- Raycast-based CityObject identification via UV coordinates
- Dynamic tile loading based on camera distance
- Road network data structures (lanes, intersections, sidewalks)
- CityObjectType hierarchy with Japanese display names
- GML file metadata access (grid code, EPSG, feature type)
- Structured city model import with PLATEAUInstancedCityModel
Import CityGML files and place them in the scene.
var importer = PLATEAUImporter.new()
importer.gml_path = "path/to/your.gml"
importer.import_gml()
add_child(importer)Load CityGML files and extract meshes.
var city_model = PLATEAUCityModel.new()
city_model.load("path/to/your.gml")
var options = PLATEAUMeshExtractOptions.new()
options.min_lod = 1
options.max_lod = 2
var mesh_data_array = city_model.extract_meshes(options)Represents extracted mesh data with attribute information.
# Access mesh and transform
var mesh: ArrayMesh = mesh_data.get_mesh()
var transform: Transform3D = mesh_data.get_transform()
# Access CityObject attributes
var gml_id: String = mesh_data.get_gml_id()
var type: int = mesh_data.get_city_object_type()
var type_name: String = mesh_data.get_city_object_type_name()
var attributes: Dictionary = mesh_data.get_attributes()
# Get specific attribute (supports nested keys with "/" separator)
var building_id = mesh_data.get_attribute("bldg:buildingID")
var height = mesh_data.get_attribute("bldg:measuredHeight")
# Get GML ID from raycast hit UV (for CityObject identification)
var gml_id_from_hit = mesh_data.get_gml_id_from_uv(hit_uv)Coordinate conversion between geographic and local coordinates.
var geo_ref = PLATEAUGeoReference.new()
geo_ref.zone_id = 9 # Tokyo
var local_pos = geo_ref.project(Vector3(35.6762, 139.6503, 0)) # lat, lon, heightOptions for mesh extraction (LOD, granularity, textures, etc.).
var options = PLATEAUMeshExtractOptions.new()
options.min_lod = 0
options.max_lod = 3
options.mesh_granularity = 1 # 0=atomic, 1=primary, 2=area
options.export_appearance = trueRoot node for imported PLATEAU city model scenes. Manages GeoReference and imported GML transforms.
var scene = PLATEAUCityModelScene.new()
scene.geo_reference = geo_ref
add_child(scene)
scene.import_gml("path/to/file.gml", import_options)
# Get latitude/longitude of origin
print("Origin: ", scene.latitude, ", ", scene.longitude)
# Get all GML transforms
for gml_transform in scene.get_gml_transforms():
print(gml_transform.name)Filter condition for city objects by type, LOD, and package.
var filter = PLATEAUFilterCondition.new()
filter.city_object_types = COT_Building | COT_Road
filter.min_lod = 1
filter.max_lod = 2
if filter.matches(mesh_data):
# Process this mesh
passStatic hierarchy of city object types with Japanese display names.
var hierarchy = PLATEAUCityObjectTypeHierarchy.new()
# Get type display name in Japanese
var name = PLATEAUCityObjectTypeHierarchy.get_type_display_name(COT_Building)
# Returns "建築物"
# Convert type to package
var package = PLATEAUCityObjectTypeHierarchy.type_to_package(COT_RoofSurface)
# Returns PACKAGE_BUILDINGDynamic tile loading manager based on camera distance. Automatically loads/unloads tiles.
var manager = PLATEAUDynamicTileManager.new()
add_child(manager)
# Set load distances per zoom level (min_distance, max_distance)
manager.set_load_distance(11, Vector2(-10000, 500)) # High detail, close range
manager.set_load_distance(10, Vector2(500, 1500)) # Medium detail
manager.set_load_distance(9, Vector2(1500, 10000)) # Low detail, far range
# Initialize with metadata store
manager.initialize(meta_store)
manager.tile_base_path = "res://tiles/"
manager.camera = $Camera3D
manager.auto_update = true
# Signals
manager.tile_loaded.connect(_on_tile_loaded)
manager.tile_unloaded.connect(_on_tile_unloaded)GML file information and utilities for accessing file metadata.
var gml = PLATEAUGmlFile.create("C:/path/to/udx/bldg/53394601_bldg_6697_op.gml")
if gml.is_valid():
print("Grid code: ", gml.get_grid_code()) # 53394601
print("Feature type: ", gml.get_feature_type()) # bldg
print("EPSG: ", gml.get_epsg()) # 6697
print("Dataset root: ", gml.get_dataset_root_path())
print("Max LOD: ", gml.get_max_lod())
# Get texture paths referenced in GML
var textures = gml.search_image_paths()
for tex_path in textures:
print("Texture: ", tex_path)
# Get geographic extent of grid code
var extent = gml.get_grid_extent()
print("Lat: ", extent.min_lat, " - ", extent.max_lat)Root node for imported PLATEAU city model. Holds metadata and provides access to child nodes.
# Created by PLATEAUImporter.import_to_scene()
var city_model: PLATEAUInstancedCityModel = importer.import_to_scene(
mesh_data_array, "MyCity", geo_reference, options, gml_path
)
add_child(city_model)
# Access metadata
print("Zone ID: ", city_model.zone_id)
print("Latitude: ", city_model.get_latitude())
print("Longitude: ", city_model.get_longitude())
print("GML Path: ", city_model.gml_path)
# Get GeoReference for coordinate conversion
var geo_ref = city_model.get_geo_reference()
# Access child transforms
for gml_transform in city_model.get_gml_transforms():
print("GML: ", gml_transform.name)
var lods = city_model.get_lods(gml_transform)
print("Available LODs: ", lods)Root container for road network data including roads, intersections, and sidewalks.
var model = PLATEAURnModel.new()
# Add roads and intersections
var road = PLATEAURnRoad.new()
model.add_road(road)
var intersection = PLATEAURnIntersection.new()
model.add_intersection(intersection)
# Build from mesh data (road package)
var model2 = PLATEAURnModel.create_from_mesh_data(road_mesh_data_array)
# Generate visualization mesh
var mesh = model.generate_mesh()The project/samples/ directory contains example scenes demonstrating SDK features.
Demonstrates how to display CityObject attributes when clicking on buildings.
- Load CityGML file and extract meshes
- Left-click on a building to show its attributes
- Displays GML ID, CityObjectType, and all attributes
Demonstrates how to color-code buildings based on their attributes.
- Color by building usage (
bldg:usage) - Color by CityObjectType
- Color by flood risk (if available in data)
Demonstrates the main PLATEAU SDK APIs with dataset folder selection.
- Dataset Selection: Select PLATEAU dataset folder, choose packages and mesh codes
- Import: Load multiple GML files with various options (LOD, granularity, textures)
- Export: Save meshes to glTF/GLB/OBJ formats
- Granularity Conversion: Convert between Atomic/Primary/Area mesh levels
Simplified version of API Sample for single GML file import.
- Single File Import: Select and load one CityGML file
- Export: Save meshes to glTF/GLB/OBJ formats
- Granularity Conversion: Convert between mesh granularity levels
- Uses PLATEAUInstancedCityModel for scene organization
Demonstrates terrain-related features.
- Load terrain GML (DEM/TIN data)
- Generate heightmap from terrain mesh
- Align buildings to terrain height
- Save heightmap as PNG image
Demonstrates map tile download features.
- Download map tiles from GSI (Geospatial Information Authority of Japan)
- Download tiles from OpenStreetMap
- Create combined texture from multiple tiles
- Apply texture to ground mesh
- Open the sample project in Godot
- Run one of the sample scenes
- Use "Import GML..." or "Load..." buttons to select your CityGML file
- Interact with the UI to test various features
Note: You need to prepare your own PLATEAU CityGML data. Download from G空間情報センター.
An editor tool for importing CityGML into your project and exporting to external formats.
Opening the Tool: Tool menu → PLATEAU Converter...
Import CityGML files as .tscn scenes into your Godot project.
- Scene Structure: Creates
PLATEAUInstancedCityModelas root node - Mesh Resources: Saves meshes as separate
.resfiles for better performance - Texture Handling: Copies textures from external PLATEAU dataset to project folder
- LOD Auto-Switch: Optional distance-based LOD switching using
visibility_range
Usage:
- Click "Import GML..." to select a CityGML file
- Configure import options (LOD range, granularity, textures)
- Enable "LOD auto-switch" if you want distance-based LOD switching
- Click "Import to Project" and select output folder
- The scene is saved as
.tscnwith mesh resources in ameshes/subfolder
Export loaded meshes to external 3D formats for use in other applications.
- Supported Formats: glTF (.gltf), GLB (.glb), OBJ (.obj)
- Use Cases: External 3D software, mobile apps, web viewers
Usage:
- Load a CityGML file using "Import GML..."
- Select export format (glTF/GLB/OBJ)
- Click "Export to File" and choose destination
- Python 3.8+
- SCons 4.0+
- CMake 3.17+
- Visual Studio 2022 (Windows) / Ninja + Xcode (macOS)
- Git
Install the following packages:
# Ubuntu/Debian
sudo apt-get install libgl1-mesa-dev libglu1-mesa-devInstall the following Homebrew packages:
brew install mesa-glu xz libdeflate ninjaSCons automatically builds libplateau and godot-plateau together.
git clone --recursive https://github.com/shiena/godot-plateau.git
cd godot-plateau# Windows (template_debug)
scons platform=windows target=template_debug
# Windows (template_release)
scons platform=windows target=template_release
# macOS
scons platform=macos target=template_release
# Linux
scons platform=linux target=template_release
# Android (requires ANDROID_HOME or ANDROID_SDK_ROOT environment variable)
scons platform=android arch=arm64 target=template_release
# iOS (requires macOS with Xcode)
scons platform=ios arch=arm64 target=template_releaseThe built library will be copied to bin/<platform>/ and project/addons/plateau/<platform>/.
# Skip libplateau build (if already built)
scons platform=windows target=template_release skip_libplateau_build=yes
# macOS: Custom Homebrew prefix (default: /opt/homebrew)
scons platform=macos target=template_release homebrew_prefix=/usr/local
# Linux: Use Clang instead of GCC (for GCC 15+ environments)
scons platform=linux target=template_release use_clang=yesANDROID_HOMEorANDROID_SDK_ROOTenvironment variable set to Android SDK path- Android NDK installed (default version: 23.1.7779620)
- Ninja build tool
# Example with custom NDK version
scons platform=android arch=arm64 target=template_release ndk_version=23.1.7779620- macOS with Xcode and Command Line Tools installed
- Ninja build tool (
brew install ninja)
git clone --recursive https://github.com/shiena/godot-plateau.git
cd godot-plateaucmake -S libplateau -B build/windows/libplateau -G "Visual Studio 17 2022" -DPLATEAU_USE_FBX=OFF -DCMAKE_BUILD_TYPE:STRING="Release" -DBUILD_LIB_TYPE=static -DRUNTIME_LIB_TYPE=MT
cmake --build build/windows/libplateau --config Releasecmake -S . -B build -G "Visual Studio 17 2022"
cmake --build build --config ReleaseThe built DLL will be copied to bin/windows/ and project/bin/windows/.
godot-plateau/
├── src/
│ ├── register_types.cpp/h
│ └── plateau/
│ ├── plateau_city_model.cpp/h # CityModel, MeshData classes
│ ├── plateau_geo_reference.cpp/h # Coordinate conversion
│ ├── plateau_importer.cpp/h # Scene builder
│ ├── plateau_mesh_extract_options.cpp/h
│ ├── plateau_gml_file.cpp/h # GML file metadata
│ ├── plateau_instanced_city_model.cpp/h # Imported city model root
│ ├── plateau_city_model_scene.cpp/h # CityModelScene, FilterCondition
│ ├── plateau_city_object_type.cpp/h # Type hierarchy
│ ├── plateau_dynamic_tile.cpp/h # Dynamic tile loading
│ └── plateau_road_network.cpp/h # Road network data
├── doc_classes/ # API documentation XML files
├── project/
│ ├── bin/
│ │ └── godot-plateau.gdextension
│ └── samples/
│ └── plateau_utils.gd # Sample utility functions
├── libplateau/ # Submodule
├── godot-cpp/ # Submodule
├── SConstruct # SCons build script (recommended)
├── CMakeLists.txt # CMake build script (alternative)
└── methods.py # SCons helper functions
When exporting to OBJ format, libplateau creates one group per CityObject (building). If you have many buildings (e.g., 1990), the exported OBJ will have that many groups. When re-importing such OBJ files into Godot, you may encounter MAX_MESH_SURFACES errors because Godot limits meshes to 256 surfaces.
Workaround: Use AREA granularity (mesh_granularity = 2) before exporting to merge buildings into fewer meshes.
The following classes are not available on mobile platforms due to libpng dependency in height map generation:
PLATEAUTerrain- Height map generation from terrain meshesPLATEAUHeightMapData- Height map data containerPLATEAUHeightMapAligner- Building height alignment to terrainPLATEAUVectorTileDownloader- Map tile downloadingPLATEAUTileCoordinate- Tile coordinate utilitiesPLATEAUVectorTile- Downloaded tile information
Core functionality (CityGML loading, mesh extraction, coordinate conversion) works on all platforms.
This project is not affiliated with, endorsed by, or sponsored by the Godot Foundation or Japan's Ministry of Land, Infrastructure, Transport and Tourism (MLIT).
- "Godot" and the Godot logo are registered trademarks of the Godot Foundation.
- "PLATEAU" is a project by the Ministry of Land, Infrastructure, Transport and Tourism of Japan.
- godot-plateau: MIT License
- libplateau: See libplateau/LICENSE