{"id":37037051,"url":"https://github.com/geodan/i3dm.export","last_synced_at":"2026-02-17T16:05:07.089Z","repository":{"id":46600013,"uuid":"304262351","full_name":"Geodan/i3dm.export","owner":"Geodan","description":"Export 3D Instanced Tiles from PostGIS table","archived":false,"fork":false,"pushed_at":"2025-10-30T12:23:16.000Z","size":51746,"stargazers_count":46,"open_issues_count":2,"forks_count":26,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-10-30T14:22:40.660Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Geodan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-10-15T08:39:39.000Z","updated_at":"2025-10-30T12:19:38.000Z","dependencies_parsed_at":"2023-02-16T07:30:39.465Z","dependency_job_id":"21460fc8-a9f9-46f0-97ff-a9342fca9c79","html_url":"https://github.com/Geodan/i3dm.export","commit_stats":{"total_commits":204,"total_committers":3,"mean_commits":68.0,"dds":0.06862745098039214,"last_synced_commit":"e3251374a444feb00f8be127361bb139a1b8a97a"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/Geodan/i3dm.export","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geodan%2Fi3dm.export","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geodan%2Fi3dm.export/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geodan%2Fi3dm.export/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geodan%2Fi3dm.export/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Geodan","download_url":"https://codeload.github.com/Geodan/i3dm.export/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geodan%2Fi3dm.export/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409482,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T04:24:31.987Z","updated_at":"2026-02-17T16:05:07.075Z","avatar_url":"https://github.com/Geodan.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# i3dm.export\n\nConsole tool for exporting Instanced 3D Models (i3dm's or glb's with EXT_mesh_gpu_instancing), i3dm composites (cmpt), subtree files and tileset.json from PostGIS table. \n\nThe input table contains instance information like location (epsg:4326), binary glTF model (glb), scale, rotation and instance attributes. \n\nThe 3D tiles created by this tool are tested in Cesium JS.\n\nSample of trees in Cesium viewer using instanced 3D Tiles in Lyon:\n\n![image](https://github.com/Geodan/i3dm.export/assets/538812/f67c6126-64be-42a9-9ee5-8f64c452c4aa)\n\n\nFor instanced 3D Model (i3dm) specs see https://github.com/CesiumGS/3d-tiles/tree/master/specification/TileFormats/Instanced3DModel\n\nFor composite tile (cmpt) specs see https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Composite/README.md\n\n[![NuGet Status](http://img.shields.io/nuget/v/i3dm.export.svg?style=flat\n)](https://www.nuget.org/packages/i3dm.export/)\n\n## Installation\n\nOptions:\n\n1] Use pre-built binaries from release\n\n2] Use .NET Tool\n\nPrerequisite: .NET 8.0 SDK is installed https://dotnet.microsoft.com/download/dotnet/8.0\n\n```\n$ dotnet tool install -g i3dm.export\n```\n\nOr update\n\n```\n$ dotnet tool update -g i3dm.export\n```\n\n3] Use Docker\n\n```\n$  docker run geodan/i3dm.export\n```\n\n## Live demo 3D instanced tiles\n\nTrees sample with implicit tiling:\n\nhttps://geodan.github.io/i3dm.export/samples/traffic_lights/cesium/\n\n## Input database table\n\nInput database table contains following columns: \n\n. geom - geometry with Point or PointZ for instance positions;\n\n. scale - double with instance scale (all directions);\n\n. rotation - double with horizontal rotation angle (0 - 360 degrees) (legacy, used in i3dm / non-GPU mode);\n. yaw - double with yaw/heading in degrees (clockwise-positive);\n. pitch - double with pitch in degrees;\n. roll - double with roll in degrees;\n\n. tags - json with instance attribute information;\n\n. model - byte[] or string column with glb or name of binary glTF model per instance. Should be valid path on tool runtime or valid uri on display in client; \n\n. (optional) scale_non_uniform - double precision[3] - for scale per instance in 3 directions.\n\nSee [testdata/create_testdata.sql](testdata/create_testdata.sql) for script creating sample table. \n\n## Parameters\n\nTool parameters:\n\n```\n-c: (required) connection string to PostGIS database\n\n-t: (required) table with instance positions\n\n-g: (optional - Default: 1000) Geometric error\n\n-o: (optional - Default: ./tiles) Output directory, will be created if not exists\n\n-q: (optional - Default: \"\") Query to add to the where clauses (for example: -q \"id\u003c5460019\"). Be sure to check indexes when using this option.\n\n--use_scale_non_uniform: (optional - default false) Use column scale_non_uniform for scaling instances\n\n--max_features_per_tile (optional - default 1000). Maximum number of features/instances of tile\n\n--geometrycolumn: (optional - default: geom) Geometry column name\n\n--use_gpu_instancing (optional - default false) Use GPU instancing (only for Cesium)\n\n--boundingvolume_heights (option - default: 0,10) - Tile boundingVolume heights (min, max) in meters. The heights will be added to the z_min and z_max values of the input geometries.\n\n--tileset_version (optional - default \"\") - Tileset version\n\n--use_i3dm (optional - default false) Use I3dm format  - only first model will be processed (false creates Cmpt - Only when creating I3dm's)\n\n--use_external_model: (optional - default false) Use external model instead of embedded model (Only when creating I3dm's)\n\n--use_clustering: (optional - default false) If tile contains more than max_features_per_tile instances, its number of instances will be reduced to max_features_per_tile by clustering\n\n--keep_projection: (optional - default false) Keep the original projection of the input table. \n```\n\n## Projection support\n\nThe input table can defined in\n\n1] Global coordinates \n\nWGS84 longitude, latitude in degrees + height in meters with ellipsoid as reference (EPSG:4979)\n\n2] Local coordinates (for release 2.12.0 and higher)\n\nAny projected coordinate system height in meters with geoid as reference\n\nFor example in the Netherlands use composite EPSG:7415 (Amersfoort / RD New (EPSG:28992) + NAP height in meters (EPSG:5709)).\n\nOn runtime the tool will reproject the instance positions to EPSG:4978 (ECEF coordinates) for creating the 3D tiles.\n\nWhen option keep_projection is set to true, the original projection of the input table is preserved and used for creating the 3D tiles. Note that when using \nthis option, the client application must support the original projection of the input table for correctly \ndisplaying the Instanced 3D Tiles, like 3DTilesRenderer/Giro3D/ITowns/QGIS Web Client (QWC). \n\n## Docker\n\nSee https://hub.docker.com/r/geodan/i3dm.export\n\nTo run in Docker mount drives:\n\n- /app/output: mount for the result tileset.json, subtree files and content files;\n\n- /glb: mount when using file based input glb's - remember to add the /glb path to the model in the database. For example  '/glb/my_model.glb'.\n\n Example:\n\n```\n$ docker run -it -v $(pwd)/output:/app/output -v $(pwd)/glb:/glb geodan/i3dm.export -c \"database_connection_string\" -t table \n```\n\n## Sample running\n\n```\n$ i3dm.export -c \"Host=localhost;Username=postgres;Password=postgres;Database=test;Port=5432\" -t public.trees\n```\n\n## Getting started\n\nFor getting started with i3dm.export tool see [getting started](docs/getting_started.md).\n\n## Technical documentation (transforms)\n\nFor a detailed explanation of how instance transforms are computed (ECEF/ENU to glTF Y-up, handedness, matrix conventions, and GPU instancing TRS composition), see:\n\n- [Technical notes: coordinate systems \u0026 transforms](docs/technical-transforms.md)\n\n## Benchmarking\n\n1] Benchmark on Daily Digital Obstacles files\n\nSource: https://www.faa.gov/air_traffic/flight_info/aeronav/digital_products/dailydof/\n\n588094 instances worldwide, Content tiles generated: 2345, Subtree files generated: 372\n\nTime generating I3dm --use_gpu_instancing false: 0h 0m 43s 799ms\n\nTime generating GLB --use_gpu_instancing true: 0h 0m 47s 879ms\n\n## Model\n\nBy default, the instance model is embedded directly in the i3dm payload. In the i3dm header, the value gltfFormat is set to 1. In this case, the model must be provided as a valid file path to a binary glTF (.glb) file. Only the i3dm files need to be copied to the production server.\n\nWhen the parameter use_external_model is set to true, the i3dm payload contains only the model name instead of the embedded binary glTF. In the i3dm header, the value gltfFormat is set to 0. In this case, the model must be specified as a valid absolute or relative URL pointing to a binary glTF (.glb) file. The client application is responsible for downloading the binary glTF files. Both the i3dm files and the referenced binary glTF files must be copied to the production server.\n\nThe use_external_model option is only available when --use_gpu_instancing is set to false.\n\n## Composites\n\nStarting with release 2.0, every tile is generated as a composite tile (.cmpt), even if the tile contains only one model.\n\nAccording to the OGC 3D Tiles specification (https://docs.opengeospatial.org/cs/18-053r2/18-053r2.html#249\n), a composite tile (cmpt) can contain multiple tile formats. In this implementation, each composite tile contains a collection of instanced 3D model tiles (i3dm).\n\nFor each unique model in a tile, one i3dm file is created. The resulting .cmpt file bundles all i3dm tiles for that tile. Even if there is only a single model, it is still wrapped inside a .cmpt file.\n\nMultiple models are supported. You can specify different models in the model column (for example, a deciduous tree model and a conifer tree model). For each unique model, a separate i3dm tile is generated. If multiple models are present in the same tile, the composite tile (.cmpt) will contain multiple i3dm files, one for each unique model.\n\nIf the option --use_i3dm=true is set, only i3dm tiles are created and no composite (.cmpt) tile is generated. When multiple models are present in a tile and --use_i3dm=true is used, only the first model is processed.\n\n## Implicit tiling\n\nStarting release 2.0, tiles are generated according to the 3D Tiles 1.1 Implicit Tiling technique. Tiles are generated in a quadtree, maximum number of features/instances is defined by parameter 'implicit_tiling_max_features'. \n\nContent tiles will be generated in output folder 'content', subtree files will be created in folder 'subtrees'. In the root output folder file 'tileset.json' will be created.\n\n## Instance batch info\n\nTo add batch info to instanced tiles fill the 'tags' type json column in the input table.\n\nFor example:\n\n```\n[{\"customer\" : \"John Doe\"}, {\"id\" : 5454577}]\n```\n\nNote: \n\n. all instance records per tile should have the same properties (in the above case 'customer' and 'id'). \nThe list of properties is determined from the first instance in the tile;\n\n. only key - value is supported, not more complex structures.\n\nSample to update the json column in PostgreSQL:\n\n```\npostgres=# update  i3dm.my_table set tags = json_build_array(json_build_object('customer','John Doe'), json_build_object('id',id));\n```\n\nThe batch table information in the i3dm tile is stored as follows (for 2 instances):\n\n```\n{\"customer\":[\"John Doe\",\"John Doe2\"], \"id\": [5454577, 5454579]}\n```\n\n## Bounding volume\n\nThe root bounding volume in Tileset.json is calculated from the input table in 3 dimensions (xmin, ymin, xmax, ymax, zmin, zmax). \n\n- The values for the boundingbox (xmin, ymin, xmax, ymax) are increased by 10%;\n    \n- The height values (zmin, zmax) are increased by the value of setting 'boundingvolume_heights' (default 0,10).\n\nNote: Positions outside xmin, ymin, xmax, ymax -180, -90, 180, 90 in wgs84 are not supported.  \n\n## Scale non uniform\n\nWhen the instance model should be scaled in three directions (x, y, z) use the --use_scale_non_uniform option (default false)\n\nWhen using this option, the column 'scale_non_uniform' will be used for scaling instances.\n\nColumn 'scale_non_uniform' must be of type 'double precision[3]'.\n\nSample queries to create/fill this column:\n\nCreate column:\n\n```\npostgres=# ALTER TABLE traffic_signs_instances\npostgres=# ADD COLUMN scale_non_uniform double precision[3]\n```\n\nFill column:\n\n```\npostgres=# update traffic_signs_instances set scale_non_uniform = '{10.0, 20.0, 30.0}'\n```\n\n## Spatial index\n\nWhen using large tables create a spatial index on the geometry column:\n\n```\npsql\u003e CREATE INDEX ON m_table USING gist(geom)\n```\n\n## GPU Instancing\n\nIn 3D Tiles 1.1, GPU instancing is supported. This means that the same model can be used for multiple instances within a glTF (using EXT_mesh_gpu_instancing -\nhttps://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing/README.md). \nFiles like I3dm/cmpt are no longer created.\n\nAttribute information can be added to the instances using glTF 2.0 extensions \n\n- EXT_instance_features - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_instance_features\n\n- EXT_structural_metadata - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata\n\nThere is an experimental option to create 3D Tiles 1.1 using GPU instancing: --use_gpu_instancing (default false).\n\nThis option is currently in development. \n\nLive demo trees in Grenoble with GPU instancing and metadata:\n\nhttps://bertt.github.io/cesium_3dtiles_samples/samples/1.1/grenoble_trees/\n\n![image](https://github.com/Geodan/i3dm.export/assets/538812/038ee19d-7f52-4102-a60c-4ece0672a6a4)\n\nThe following features should work: \n\n- Attribute information from tags; \n\n- Positioning, Rotation (roll, pitch, yaw) and Scaling of instances.\n\nTo use this option, the input table should contain columns 'roll', 'pitch' and 'yaw' (column 'rotation' is not used).\n\nSql script to create the columns:\n\n```\nalter table instances add yaw decimal default 0\nalter table instances add pitch decimal default 0\nalter table instances add roll decimal default 0\nalter table instances drop column rotation\n```\n\n### External textures\nWhen the input model (GLB/GLTF) references external image textures (for example `*.png`), GPU instancing tiles are written as GLB files that reference those textures externally instead of embedding them in every tile.\n\nOn export, textures are written once to:\n\n- `output\\\\content\\\\textures\\\\\u003cmodelName\u003e\\\\\u003ctextureFile\u003e`\n\nand each generated tile GLB references them via a relative URI:\n\n- `textures/\u003cmodelName\u003e/\u003ctextureFile\u003e`\n\nThis significantly reduces dataset size when many tiles share the same model + textures.\n\nIf the input model has embedded images, they remain embedded in each exported tile GLB.\n\n### Known limits\n\n- When using GPU instancing, for the attributes the 'string' type is used (so no support for other types yet);\n\n- No support for multiple meshes/nodes in the input model;\n\n- composite tiles (formerly known as cmpt). Support is added for multiple models in a tile (like multiple models in a composite cmpt file). There is a known issue with showing the attribute information in Cesium. See https://github.com/CesiumGS/cesium/issues/11683\n\nWarning: When the input glTF model has transformations, the model will be transformed twice: once in the glTF and once for the instance translations. In some \ncases it's better to remove the transformations from the input model. For example tool 'gltf-tansform' - function clearNodeTransform (https://gltf-transform.dev/modules/functions/functions/clearNodeTransform) can be \nused to clear local transformations.\n\n### Known issues GPU Instancing\n\n- Getting attributes in Cesium does not work when there are multiple input models\nhttps://community.cesium.com/t/upgrade-3d-tileset-with-composite-cmpt-tile-to-1-1-attribute-data-missing/33177/2\n\n## Clustering\n\nThere is an experimental option to create 3D Tiles using clustering: --use_clustering (default false).\n\nWhen this option is off, dense tiles with number of instances exceeding `max_features_per_tile` aren't rendered. With this option such tiles are rendered with number of instances that is exactly equal to `max_features_per_tile`. Number of instances is reduced in the following way:\n\n- tile instances are clustered with MiniBatchKMeans algorithm with number of clusters equal to `max_features_per_tile`;\n- from each cluster single instance is picked randomly.\n\n### Performance benchmark\nnumber of instances: 2500\u003cbr\u003e\nmax_features_per_tile: 100\u003cbr\u003e\n\ntileset generation time:\n- without clustering : 0h 0m 0s 539ms\n- with clustering: 0h 0m 1s 238ms\n## Developing\n\nRun from source code:\n\n```\n$ git clone https://github.com/Geodan/i3dm.export.git\n$ cd i3dm.export/src\n$ dotnet run -- -c \"Host=myserver;Username=postgres;Password=postgres;Database=test;Port=5432\" -t public.trees\n```\n\nTo develop in Visual Studio Code, open .vscode/launch.json and adjust the 'args' parameter to your environment\n\n```\n\"args\": [\"-c\" ,\"Host=myserver;Username=postgres;Database=test;Port=5432\", \"-t\", \"my_table\"],\n```\n\nPress F5 to start debugging.\n\n## History\n\n2026-02-17: release 2.15.0: improve gpu instancing picking for multi node model and fix for pitch, roll, yaw rotations\n\n2026-02-13: release 2.14.1: fix for keep_projection option\n\n2026-02-13: release 2.14.0: add support for keep_projection and add support for external textures when using GPU instancing\n\n2026-02-05: release 2.13.0: fix clustering status messages\n\n2024-10-30: release 2.12.0: add support for cartesian projected input coordinates \n\n2024-12-20: release 2.11.0: add clustering + change ellipsoid \n\n2024-10-31: release 2.10.0: add multiple mesh support in input model + gpu instancing tags null checking + vertical precision\n\n2024-10-15: release 2.9.0: add tileset version option\n\n2024-08-01: release 2.8.3: fix release\n\n2024-08-01: release 2.8.2: fix for I3dm using rtc_center for high precision positions\n\n2024-07-22: release 2.8.1: fix release\n\n2024-07-22: release 2.8.0: to .NET 8.0\n\n2024-06-20: release 2.7.4: fix for composite tiles when using GPU instancing\n\n2024-06-13: release 2.7.3: add support for other input source EPSG codes than 4326\n\n2024-06-10: release 2.7.2: fix gpu instancing yaw, pitch, roll, remove mapbox code (parameter -f --format)\n\n2024-06-08: release 2.7.1: fix for disappearing instances \n\n2023-03-28: release 2.7.0: add support for EXT_structural_metadata\n\n2023-11-08: release 2.6.0: Add support for GPU instancing (experimental), removed option -r RTC_CENTER \n\n2023-10-18: release 2.5.0: Improved root bounding volume calculation, improved batch table handling\n\n2023-09-27: release 2.4.5: Get boundingvolume z from input table + option boundingvolume_heights removed\n\n2023-09-27: release 2.4.4 change default -r (relative positions) from false to true\n\n2023-06-20: release 2.4.3 fix for generating 1 tile\n\n2023-02-21: release 2.4.1 fix version number\n\n2023-02-21: release 2.4 split root subtree file in multiple subtree files\n\n2023-01-30: release 2.3.2 improve spatial index performance \n\n2022-10-05: release 2.3.1 bug fix for showing all instances per tile\n\n2022-10-05: release 2.3 add support for byte[] type column (in addition to string) for glb's from database\n\n2022-08-31: release 2.2 renamed parameter 'implicit_tiling_max_features' to 'max_features_per_tile', \nfix skewed bounding volumes\n\n2022-08-09: release 2.1 use 1 geometric error as input parameter\n\n2022-08-08: release 2.0 adding 3D Tiles 1.1 Implicit Tiling. \n\nBreaking change: \n\nParameters removed: -e and -s (extent tile and super extent tile)\n\nParameters added: implicit_tiling_max_features (default 1000)\n\n2021-10-04: release 1.9 adding Cesium support\n\n2020-11-12: release 1.8 add external tileset support\n\n2020-11-12: release 1.72. to .NET 5.0\n\n2020-11-05: release 1.7.1 with bug fix wrong instances per i3dm when multiple models used. \n\n2020-11-05: release 1.7 add support for composite tiles (cmpt). Breaking change: parameter -m --model is removed. \nModel can now be defined per instance in the input table.\n\n2020-10-28: release 1.6 add scale_non_uniform support\n\n2020-10-21: release 1.5 add query, use_external_model parameters\n\n2020-10-20: release 1.4 add batch info support\n\n2020-10-20: release 1.3 adding instance rotation + rtc_Center support \n\n2020-10-19: release 1.2 with instance scale support\n\n2020-10-19: add support for uri references to external glTF's.\n\n2020-10-15: Initial coding\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeodan%2Fi3dm.export","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeodan%2Fi3dm.export","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeodan%2Fi3dm.export/lists"}