Taos Engine ▦ Taos: API Documentation

3 — Tileset & Imagery Layers

Live demo: run this tutorial in your browser — built from src/03_layers.ts.

A GeoScene is a stack of datasets. This tutorial layers terrain, buildings, and photorealistic 3D Tiles into one scene, then drapes multi-layer imagery (an aerial base map with a transparent labels overlay) onto the terrain. Sources: samples/geo_osm.ts, samples/geo_imagery.ts, src/geo/geo_scene.ts.

The four kinds of tileset#

GeoScene has one add* method per data type. Each returns { tileset, ready } immediately; ready resolves when the root tile loads.

geo.addTerrain(asset, opts);            // Cesium quantized-mesh terrain (ion)
geo.addRasterDemTerrain(source, opts);  // Web-Mercator PNG-elevation terrain (e.g. AWS Terrarium)
geo.add3DTiles(asset, opts);            // 3D Tiles: buildings, city models, photorealistic
geo.addVectorTiles(source, opts);       // vector tiles (MVT) draped on terrain

Stacking order matters#

Add terrain first, then things that sit on it. Buildings and other content clamp their height against the terrain that's already loaded, so terrain has to be in the scene before them:

import { GeoScene, GeoFrame } from 'taos/geo/index.js';
import { AWS_TERRARIUM, ESRI_WORLD_IMAGERY, OPENFREEMAP_VECTOR } from 'taos/geo/index.js';

const geo = new GeoScene(device, GeoFrame.atLonLat(-74.0060, 40.7128, 0));

// 1. Terrain underneath everything (keyless AWS Terrarium, draped with imagery).
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: ESRI_WORLD_IMAGERY });

// 2. OSM building footprints on top (keyless OpenFreeMap vector tiles).
geo.addVectorTiles(OPENFREEMAP_VECTOR);

The keyed equivalents are a drop-in swap (same GeoScene API): addTerrain( resolveIonAsset(ION_ASSETS.worldTerrain, token)) for Cesium quantized-mesh world terrain and add3DTiles(resolveIonAsset(ION_ASSETS.osmBuildings, token)) for the Cesium OSM Buildings 3D Tileset — both higher-fidelity, both needing an ion token.

Swapping OSM for full photorealistic 3D Tiles is a one-line change — point add3DTiles at Google's photorealistic asset instead:

geo.add3DTiles(await resolveIonAsset(ION_ASSETS.googlePhotorealistic, ION_TOKEN));

(Photorealistic tiles already include terrain and buildings, so you'd usually drop the separate terrain/OSM layers when using them.)

Per-tileset options#

add3DTiles takes GeoTilesetOptions:

geo.add3DTiles(asset, {
  lit: true,            // light otherwise-unlit materials (default true)
  albedoBoost: 1.2,     // brighten dark content
  collision: false,     // retain CPU triangle soup for physics (tutorial 9)
  useWorker: () => true,// decode tiles off the main thread
  // bodyOffset, regionEllipsoid — for non-Earth bodies (tutorial 10)
});

Tune the LOD aggressiveness per tileset after it's added:

const { tileset, ready } = geo.add3DTiles(asset);
await ready;
tileset.maxSSE = 12;   // target screen-space error in px (default 16; lower = sharper, heavier)

Imagery: draping a texture on terrain#

Quantized-mesh and raster-DEM terrain are geometry only — they get their color from an imagery provider draped over them. Pass one via the terrain options:

import { ESRI_WORLD_IMAGERY, OSM_RASTER, CARTO_LIGHT } from 'taos/geo/index.js';
import { AWS_TERRARIUM } from 'taos/geo/index.js';

geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: ESRI_WORLD_IMAGERY });  // aerial photos
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: CARTO_LIGHT });          // clean map style
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: false });               // no drape (bare geometry)

imagery: true (or omitting it) uses ESRI_WORLD_IMAGERY by default. Built-in providers (no API key needed for most): ESRI_WORLD_IMAGERY, OSM_RASTER, CARTO_LIGHT, CARTO_DARK, CARTO_LIGHT_LABELS, CARTO_DARK_LABELS, CARTO_LIGHT_RETINA, STADIA_ALIDADE_SMOOTH, STADIA_ALIDADE_DARK.

Your own XYZ tile source#

import { xyzImagery } from 'taos/geo/index.js';

const myTiles = xyzImagery({
  label: 'My Tiles',
  attribution: '© Me',
  template: 'https://my-server.com/{z}/{x}/{y}.png',  // {s} subdomain optional
  maxZoom: 18,
});
geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: myTiles });

Multi-layer imagery: base map + labels#

A single provider is one image. To composite several — say an aerial base with a transparent street-labels overlay — build an ImageryStack. Each layer is a provider plus optional photographic adjustments (alpha, brightness, contrast, gamma, saturation, hue). They're alpha-composited into one texture before draping, so the terrain path is unchanged.

import { imageryStack, ESRI_WORLD_IMAGERY, CARTO_LIGHT_LABELS } from 'taos/geo/index.js';

geo.addRasterDemTerrain(AWS_TERRARIUM, {
  imagery: imageryStack(
    { provider: ESRI_WORLD_IMAGERY, brightness: 1.05, contrast: 1.05 },  // base
    { provider: CARTO_LIGHT_LABELS, alpha: 0.9 },                         // labels on top
  ),
});

Layers composite bottom-to-top — the first argument is the base, each later one draws over it. CARTO_*_LABELS providers are transparent label-only tiles designed exactly for this overlay role.

samples/geo_imagery.ts wires these into live sliders (base picker, label opacity, brightness/contrast/saturation) and re-streams the terrain when they change — a good reference for a runtime imagery control panel.

Switching the whole stack at runtime#

To swap datasets (e.g. toggle between ion and AWS terrain), clear() the scene and rebuild:

async function rebuild(useIon: boolean): Promise<void> {
  geo.clear();                              // remove all tilesets + caches
  if (useIon) {
    geo.addTerrain(ionTerrain, { imagery: OSM_RASTER });
    geo.add3DTiles(ionBuildings);
  } else {
    geo.addRasterDemTerrain(AWS_TERRARIUM, { imagery: OSM_RASTER });
  }
}

You can also geo.remove(tileset) to drop a single layer, or geo.setVisible(tileset, false) to hide one without unloading it (handy when the terrain is also feeding physics colliders — see tutorial 9).

Next#