Scene Importer#
The Aerial Omniverse Digital Twin is built on NVIDIA Omniverse. As such, it requires scene geometries to be in OpenUSD format. Geospatial information, however, is often available and distributed in other formats. To bridge the gap, the Aerial Omniverse Digital Twin offers a pipeline to import geospatial data from CityGML format as well as OpenStreetMap OSM.
Import via UI#
One way of running the GIS processing tools is through the UI.
Connecting to a GIS worker#
Once the GIS container is running, you can attach to the GIS worker from the UI. The connection to the worker can be configured in the GIS Channel Configuration section.

The NATS server path is the URL for the NATS server. The NATS subject is a unique prefix that enables communication with the GIS worker, ensuring multiple workers on the same node remain isolated. The server path and the subject should be the same ones used to start up the channel listener in the GIS container.
Note: The GIS subject must be different from the EM worker subject. The connection will not be allowed otherwise. This is to prevent interference when an EM worker and a GIS worker are attached simultaneously.
Once set, click Attach Worker to attach to an available GIS worker. After the worker is attached successfully, a confirmation window should appear.
If no workers are available, the connection cannot be established, or the server is invalid, an error window will appear instead. In that case, check the server connection and that the channel listener is running on the GIS container.
Starting GIS Processing from the UI#
Once a worker is attached, we can trigger GML or OSM jobs. The progress bar below will communicate the status and progress of each job. Only one job can be run at once. Any logs generated by the UI or the GIS container will be in the Console tab of the UI with the Info filter enabled. Below are more details on how to start processing for each job type.
OpenStreetMap (OSM)#
Assuming a worker is attached, once parameters are set, we can click the Start OSM Processing button. The progress bar below will reflect progress from the GIS container, along with status logs.

When the job completes successfully, the status will read Completed successfully, and the USD file will be located in the path specified in the Output stage field. The console will contain additional information. If the job fails, the status will read Failed (check console for more info). Again, the console will contain more information about why the job failed.
CityGML#
Assuming a worker is attached, once the parameters are set, we can click the Start GML Processing button to produce the scene we want to analyze. The progress bar below will display the progress of the GIS container as it generates the scene, along with status logs.

When the job completes successfully, the status will read Completed successfully, and the USD file will be located in the path specified in the Output stage field. If the job fails, the status will read Failed (check console for more info), and the console will contain additional details.
Import via command line interface (CLI)#
We may also use the CityGML and OSM import tools directly via the CLI. To do so, we need to access the container directly. First, log in to the nvcr.io container registry using the $oauthtoken username and the NGC Personal API Key:
docker login nvcr.io
Username: $oauthtoken
Password: <NGC_CLI_API_KEY>
More information about NGC_CLI_API_KEY can be found at NGC - User’s Guide. As discussed in the Installation section, the key used should be the ‘Personal Key’ tied to the Aerial-OV-Digital-Twin organization.
Next, we can run:
docker run --rm -it -v <local data>:/src/aodt_gis/data --pull=always nvcr.io/nvidia/aerial/aodt-gis:1.3.1 /bin/bash
where <local data> is the local folder where the source data is stored.
CityGML Import#
Once inside the container, the GML import script can be accessed with
cd /src/aodt_gis/aodt_py/aodt_ui_gis
python3 gis_jobs/gml_job.py
and it has the following parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
This argument specifies the URL/s of the source data. |
|
Yes |
This argument specifies the URL where the USD scene needs to be saved. |
|
N️o |
If set, the pipeline will perform a conversion between input and output coordinate reference systems, as defined by their EPSG codes. Currently, only the transform from geographic coordinate systems (angular units) to projected coordinate systems (linear units) is supported. For example, a transform from EPSG:6697 to EPSG:32654 would be expressed as |
|
N️o |
Specifies whether or not procedurally-generated indoor spaces are to be created. |
|
No |
When present, terrain is built from publicly available elevation data. |
|
N️o |
Creates rougher cuts in the mobility mesh, i.e., not as tight to the footprint geometry. It may be used in particularly complicated or large scenes. |
For example, to import a portion of Tokyo from PLATEAU, we can run a script to download the Tokyo CityGML bundle to our data folder.
cp /src/aodt_gis/samples/get_tokyo.bash /src/aodt_gis/data
sh /src/aodt_gis/samples/get_tokyo.bash
rm -r /src/aodt_gis/data/get_tokyo.bash
Next, we can run the command
python3 gml_job.py -i /src/aodt_gis/data/13100_tokyo23-ku_2022_citygml_1_2_op/udx/bldg/53393599_bldg_6697_2_op.gml -epsg_in 6697 --epsg_out 32654 -o /src/aodt_gis/data/tokyo_small.usd
The parameters
-epsg_in 6697 -epsg_out 32654
indicate that we are projecting from the source coordinate reference system (EPSG 6697) to the UTM (Universal Transverse Mercator) zone 54N.
Indoor spaces will be procedurally generated unless the following parameter is passed:
--disable_interiors True
Indoor spaces are created based on the building footprint per floor. A small percentage of buildings may not have interiors due to ambiguous geometries. In those cases, the mobility domain will be consistent with the map, meaning buildings without interiors will be excluded from indoor UE mobility.
OpenStreetMap (OSM) import#
Similarly, the OSM import script can be accessed directly at
cd /src/aodt_gis/aodt_py/aodt_ui_gis/
python3 gis_jobs/osm_job.py
and it has the following parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
This argument specifies the URL where the USD scene needs to be saved. |
|
Yes |
This argument specifies the bounding box of the area of interest in decimal degrees and in the following order |
|
No |
Specifies whether or not procedurally-generated indoor spaces are to be created. |
|
No |
When present, terrain is built from publicly available elevation data. |
For example, to import a map of the area around the University of Texas - Austin, we would run the following command:
python3 gis_jobs/osm_job.py -o /src/aodt_gis/data/ut_austin.usd -c -97.74384 30.27690 -97.72444 30.29416
Sample maps#
Map name |
Source Data |
Description |
Textures |
Indoor |
|---|---|---|---|---|
|
OSM |
OSM import for the coordinates |
N |
Y |
|
A section of Kyoto defined by the following tiles. Includes DEM and procedural interiors. |
N |
Y |
|
|
Same as |
N |
Y |
|
|
A smaller and lighter map of Kyoto defined by the tile |
N |
Y |
|
|
A section of Tokyo defined by the following tiles. Includes DEM and procedural interiors. |
N |
Y |
|
|
Same as |
N |
Y |
|
|
A smaller and lighter map of Tokyo defined by the tile |
N |
Y |
|
|
This map was derived from a photogrammetry model using Blender and Omniverse. It contains layers for simulation, as well as a visualization layer that showcases the photogrammetry. |
Y |
N |
Vegetation#
Vegetation may be added via the UI only. See the GUI section for more info.
To add vegetation in bulk, import by geoJSON. The geoJSON file must contain polygons where vegetation may be placed. To make such a file, third-party tools such as geojson.io are recommended. Using such tools, polygons may be drawn over a map and exported to a file acceptable by AODT. Please note, intersections with OSM buildings, roads, and water are not allowed and will be automatically corrected in AODT upon upload.
Vegetation Placement Methodology#
Vegetation placement by geoJSON is done using a Poisson Disk Sampling algorithm in which candidate tree positions are generated across the polygons according to the specified canopy density. Then, candidate trees are filtered based on obstacles in the scene like roads, buildings, and other trees.
The target density is a theoretical maximum which is often not met exactly due to geometric constraints and obstacles in the actual plantable areas.
Elevation#
Elevation data will be imported from SRTM if indicated via the terrain_included flag. Additional terraforming will take place afterwards to align buildings to the terrain.
In the UI, the terraforming parameters are fixed. To modify these parameters directly, it is recommended to generate a map through the CLI. The following parameters are available to tune via CLI:
|| Parameter | Description |
|| :— | :— |
|| terraform | Enable terrain conformance to building base elevations |
|| pad_radius | Distance (meters) around building footprints to extend terraformed area |
|| pre_tessellation_length | Target edge length (meters) for terrain mesh tessellation |
|| pre_smooth_terrain | Smooth raw terrain before sampling building base heights |
|| pre_smooth_iters | Number of pre-smoothing iterations |
|| pre_smooth_lambda | Pre-smoothing relaxation factor (0=none, 1=max) |
|| terraform_smooth | Smooth terrain outside building footprints after terraforming |
|| terraform_smooth_iters | Number of post-terraforming smoothing iterations |
|| terraform_smooth_lambda | Post-smoothing relaxation factor (0=none, 1=max) |
|| terraform_smooth_radius | Limit smoothing to within X meters of buildings (0=entire map) |
|| building_base_method | Method to compute building base elevation: min, max, average, top10, bottom10 |
|| base_merge_distance | Distance (meters) within which buildings merge to same base height |
|| base_influence_radius | Maximum distance (meters) for building base height influence |
|| base_influence_sigma | Gaussian falloff parameter (meters) for base height smoothing |
|| base_smooth_iters | Number of iterations for building base height smoothing |
|| rough | Use robust mobility domain cutting method (recommended for complex geometries) |
The following are example commands.
For GMLs which do not have elevation data:
python3 gis_jobs/gml_job.py -i /src/aodt_gis/data/13100_tokyo23-ku_2022_citygml_1_2_op/udx/bldg/53394526_bldg_6697_2_op.gml -o /src/aodt_gis/data/test_dem_tokyo_53394526.usd -ei 6697 --include_elevation --terraform --pad_radius 8.0 --pre_tessellation_length 4.0 --pre_smooth_terrain --pre_smooth_iters 2 --pre_smooth_lambda 0.5 --terraform_smooth --terraform_smooth_iters 8 --terraform_smooth_lambda 0.6 --terraform_smooth_radius 0 --building_base_method max --base_merge_distance 175.0 --base_influence_radius 140.0 --base_influence_sigma 80.0 --base_smooth_iters 1
For OSM:
python3 gis_jobs/osm_job.py -c -105.30842 40.00553 -105.28387 40.02554 -o /src/aodt_gis/data/osm_boulder_dem.usd --include_elevation --terraform --pad_radius 8.0 --pre_tessellation_length 4.0 --pre_smooth_terrain --pre_smooth_iters 2 --pre_smooth_lambda 0.5 --terraform_smooth --terraform_smooth_iters 8 --terraform_smooth_lambda 0.6 --terraform_smooth_radius 0 --building_base_method max --base_merge_distance 50.0 --base_influence_radius 20.0 --base_influence_sigma 55.0 --base_smooth_iters 3