Build your first scenery tile

Last updated · how this page is sourced

This is the page the rest of the site exists for. TerraGear’s documentation is spread across a repository README, a how-to written in 1999, and half a dozen wiki pages that do not entirely agree with each other. What follows is a single ordered route, start to finish.

Before you begin, you need the tools built. If you have not done that, start at Installing TerraGear.

1. Pick your area

Choose the boundaries of the region you want to build, in latitude and longitude. This is the most consequential decision you will make, so make it small.

The smaller the area, the less data you download and the less CPU time the build consumes. One degree square is a good first target: the worked example on this page, N37W123, took 37 seconds end to end. Pick somewhere you know well enough to recognise when you fly over it.

2. Gather the source data

A TerraGear build draws on three separate kinds of input, and you collect each one independently:

  • Elevation; SRTM elevation files, distributed as .hgt archives.
  • Airports; an apt.dat file, uncompressed.
  • Land cover; shapefiles describing landmass, land use, roads, streams and towns.

Where to obtain each of these, and which sources are still alive, is covered in Where to get terrain data. Read that page before downloading anything: several of the sources named in the project’s older documentation have been offline for years.

3. Preprocess each kind of data

This is the first of the build’s two stages. Nothing here produces scenery yet; each tool converts one kind of raw input into the intermediate form that the final stage consumes, chopped into FlightGear’s tiling scheme.

Elevation

hgtchop cuts a .hgt file into the tiling scheme, writing one .arr.gz per tile. terrafit then fits a surface to each one and writes the .fit.gz that the final stage reads.

hgtchop 1 N37W123.hgt $WORK/SRTMGL1
terrafit -j 10 $WORK/SRTMGL1

The first argument to hgtchop is the resolution, 1 or 3 arc seconds; it takes a plain .hgt file, not the zip the README describes. Name the output directory after the data you fed it: genapts looks for SRTM-1, SRTM-3, SRTM-30, SRTMGL1 and SRTMGL3 under the work directory, and a directory called anything else will not be found.

Airports

genapts reads your apt.dat and generates the airport layouts (runways, taxiways and lighting) for the region. The name is genapts; the string genapts850 appears nowhere in the source, though it is common in older documentation.

genapts --input=apt.dat --work=$WORK \
        --min-lon=-123 --max-lon=-122 --min-lat=37 --max-lat=38 \
        --threads=4
Two things will cost you an afternoon here. Pass an uncompressed apt.dat: the version check reads gzip, the scheduler that follows it does not, so a .gz is accepted and then scanned as binary until you kill it. And keep the thread count low: --threads with no number takes your core count, and above four threads, concurrent airport builds corrupt a shared index and the run dies. It crashed on all twelve attempts at ten threads. See Common errors and fixes.

Land cover

ogr-decode decodes the shapefiles into the intermediate polygon form, one run per material. It is still called ogr-decode: no poly-decode has existed at any point in the project’s history, despite what some documentation says.

ogr2ogr -f "ESRI Shapefile" -clipsrc -123 37 -122 38 \
        clipped/landmass.shp ne_10m_land.shp ne_10m_land
ogr-decode --area-type Default --max-segment 500 \
        $WORK/Landmass clipped/landmass.shp landmass

Clip with ogr2ogr first. --spat filters features by bounding box without clipping their geometry, so one world-spanning polygon will have the tool tessellating Antarctica for your Californian tile. The full ten-layer example is on ogr-decode.

You can skip this step for a first build: pass --ignore-landmass in step 4 and you get terrain and airports without coastlines. It is also the step that decides what the build costs: adding land cover took construction from 15 seconds to 286, and peak memory from 81 MB to 2.2 GB.

4. Construct the scenery

This is the second stage, and the only one that produces scenery. tg-construct collects every intermediate piece produced in step 3 (elevation, airports, land cover) and assembles them into the 3D terrain model.

tg-construct --work-dir=$WORK --output-dir=$OUT \
             --min-lon=-123 --max-lon=-122 --min-lat=37 --max-lat=38 \
             --priorities=/usr/local/share/TerraGear/default_priorities.txt \
             --threads \
             SRTMGL1 AirportArea AirportObj

The trailing arguments are the subdirectories of the work directory to load, and the order matters: later ones win where polygons overlap. default_priorities.txt is installed alongside the binaries and governs which material takes precedence. Add --ignore-landmass if you have no land-cover layer yet; the terrain will carry elevation and airports without coastlines.

A known failure mode. tg-construct can exhaust the resources available to it and terminate itself. The wiki’s suggested remedy is to adjust setrlimit in the source. If your build dies without an obvious error, this is the first thing to check: see Common errors and fixes.

5. Load it in FlightGear

The output is FlightGear scenery. Place it where FlightGear looks for scenery, start the simulator at an airport inside your region, and you should be looking at terrain you built.

Scatter of fitted terrain nodes over one degree square. The ocean on
       the left is nearly empty; nodes crowd along the coastline and the ridges.
terrafit‘s output for this square: 15,828 fitted nodes standing in for 12,967,201 elevation posts. Nodes cluster where the ground is complex and thin out over open water. The grid is the 32 FlightGear tiles that one degree splits into.

What this guide does not yet tell you

The commands above are the ones that produced the tiles shown in step 5.

Land cover is the optional half. The first build used --ignore-landmass: elevation and airports, no coastline, no surface materials; an airport floating in open ocean, which the gallery shows literally. A second pass decoded ten layers from OpenStreetMap and Natural Earth; that is on ogr-decode.

Nothing, now. This guide was published with step 5 marked unconfirmed. It has since been rendered; on a machine with no graphics card, by the recipe on Rendering FlightGear headless: the output loads in FlightGear 2020.3.16 and renders; KSFO’s runways in the right place at the right elevation, and with land cover added, the peninsula and the bay around them. See the gallery for the three renders, including a control with no scenery at all so you can see what the tools actually contributed.

What is still worth knowing: this was one square, on one machine, in one version of FlightGear. And the land-cover pass is the expensive half; 286 seconds against 15, and 2.2 GB of memory against 81 MB.

Where the numbers come from. Every figure here was measured on one machine, for one square, once. Ten cores, 7 GB of RAM, Debian 12 in Docker; TerraGear next at commit eba49f2 against SimGear release/2024.1. Different hardware and a rougher region will give different answers. The full record, including the raw logs, is on the sources page.