or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

3d-tiles.mdanimation.mdindex.mdspatial-indexing.mdterrain.mdtile-layers.mdvector-tiles.md
tile.json

terrain.mddocs/

3D Terrain Visualization

Layer for rendering 3D terrain meshes from elevation data with texture mapping, material support, and optimized mesh generation using Martini triangulation.

Capabilities

TerrainLayer

Layer for rendering 3D terrain from heightmap data with optional texture overlays and advanced material properties.

/**
 * Layer for rendering 3D terrain meshes from elevation data
 * Uses Martini triangulation for efficient mesh generation from heightmaps
 */
class TerrainLayer extends TileLayer<MeshAttributes> {
  constructor(props: TerrainLayerProps);
}

interface TerrainLayerProps extends TileLayerProps<MeshAttributes> {
  /** Image URL template that encodes height data */
  elevationData: URLTemplate;
  
  /** Image URL template to use as texture overlay */
  texture?: URLTemplate;
  
  /** Martini error tolerance in meters, smaller number means more detailed mesh */
  meshMaxError?: number;
  
  /** Bounding box of the terrain image [minX, minY, maxX, maxY] in world coordinates */
  bounds?: number[] | null;
  
  /** Color to use if texture is unavailable */
  color?: Color;
  
  /** Object to decode height data from RGB values to height in meters */
  elevationDecoder?: ElevationDecoder;
  
  /** Supply URL to local terrain worker bundle (for offline use) */
  workerUrl?: string;
  
  /** Render terrain as wireframe */
  wireframe?: boolean;
  
  /** Material properties for terrain rendering */
  material?: Material | boolean;
  
  /** Data loaders for processing terrain data */
  loaders?: any[];
}

interface ElevationDecoder {
  /** Red channel multiplier */
  rScaler: number;
  /** Green channel multiplier */
  gScaler: number;
  /** Blue channel multiplier */
  bScaler: number;
  /** Height offset in meters */
  offset: number;
}

type MeshAttributes = {
  positions: Float32Array;
  normals?: Float32Array;
  texCoords?: Float32Array;
  indices?: Uint32Array;
};

Usage Examples:

import { TerrainLayer } from "@deck.gl/geo-layers";

// Basic terrain layer with elevation data
const terrainLayer = new TerrainLayer({
  id: 'terrain',
  minZoom: 0,
  maxZoom: 15,
  strategy: 'no-overlap',
  
  // Elevation data (e.g., Mapbox terrain-rgb tiles)
  elevationData: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token={token}',
  
  // Texture overlay (e.g., satellite imagery)
  texture: 'https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.png?access_token={token}',
  
  // Mapbox terrain-rgb elevation decoder
  elevationDecoder: {
    rScaler: 6553.6,   // (2^16 - 1) / 10
    gScaler: 25.6,     // (2^8 - 1) / 10  
    bScaler: 0.1,      // 1 / 10
    offset: -10000     // Offset for below-sea-level areas
  },
  
  // Mesh quality (lower = more detailed)
  meshMaxError: 4.0,
  
  // Styling
  color: [255, 255, 255]
});

// High-resolution terrain with custom elevation data
const highResTerrainLayer = new TerrainLayer({
  id: 'high-res-terrain',
  minZoom: 10,
  maxZoom: 16,
  
  // Custom elevation data source
  elevationData: 'https://elevation-tiles.example.com/{z}/{x}/{y}.png',
  
  // Custom elevation decoder for 16-bit grayscale heightmaps
  elevationDecoder: {
    rScaler: 0.1,    // Red channel as primary height
    gScaler: 0,      // No green channel contribution
    bScaler: 0,      // No blue channel contribution  
    offset: 0        // No offset
  },
  
  // Higher mesh quality for detailed terrain
  meshMaxError: 1.0,
  
  // Wireframe visualization
  wireframe: true,
  
  // Custom material properties
  material: {
    ambient: 0.35,
    diffuse: 0.6,
    shininess: 32,
    specularColor: [255, 255, 255]
  }
});

// Terrain with bounds and custom styling
const boundedTerrainLayer = new TerrainLayer({
  id: 'bounded-terrain',
  
  elevationData: 'https://tiles.example.com/elevation/{z}/{x}/{y}.png',
  texture: 'https://tiles.example.com/imagery/{z}/{x}/{y}.jpg',
  
  // Constrain to specific geographic bounds
  bounds: [-122.5, 37.7, -122.3, 37.9], // San Francisco area
  
  elevationDecoder: {
    rScaler: 1.0,
    gScaler: 0,
    bScaler: 0,
    offset: 0
  },
  
  // Fallback color when texture fails to load
  color: [139, 169, 19], // Olive green
  
  meshMaxError: 2.0,
  
  // Enable material lighting
  material: true
});

Elevation Data Processing

Elevation Decoding

Configure how RGB pixel values are converted to elevation heights.

interface ElevationDecoder {
  /** Multiplier for red channel (0-255) */
  rScaler: number;
  /** Multiplier for green channel (0-255) */
  gScaler: number;
  /** Multiplier for blue channel (0-255) */
  bScaler: number;
  /** Constant offset added to final height */
  offset: number;
}

/**
 * Final height calculation:
 * height = (r * rScaler) + (g * gScaler) + (b * bScaler) + offset
 */

Common Elevation Encodings:

// Mapbox Terrain-RGB encoding
const mapboxDecoder: ElevationDecoder = {
  rScaler: 6553.6,  // Red: 256 * 256 / 10
  gScaler: 25.6,    // Green: 256 / 10
  bScaler: 0.1,     // Blue: 1 / 10
  offset: -10000    // Support below-sea-level
};

// 16-bit grayscale heightmap
const grayscaleDecoder: ElevationDecoder = {
  rScaler: 0.1,     // Red channel only
  gScaler: 0,       // Ignore green
  bScaler: 0,       // Ignore blue
  offset: 0         // No offset
};

// Custom encoding with centimeter precision
const centimeterDecoder: ElevationDecoder = {
  rScaler: 65.536,  // Red: 256 * 256 / 1000
  gScaler: 0.256,   // Green: 256 / 1000
  bScaler: 0.001,   // Blue: 1 / 1000
  offset: 0
};

// USGS 1/3 arc-second DEM encoding
const usgsDecoder: ElevationDecoder = {
  rScaler: 1.0,     // Direct height values
  gScaler: 0,
  bScaler: 0,
  offset: 0
};

Mesh Generation

Martini Triangulation

TerrainLayer uses Martini algorithm for efficient terrain mesh generation from regular heightmaps.

interface MeshGenerationProps {
  /** 
   * Martini error tolerance in meters
   * Lower values create more detailed meshes with more triangles
   * Higher values create simpler meshes with fewer triangles
   */
  meshMaxError?: number;
  
  /**
   * Geographic bounds for terrain tiles
   * Used for accurate mesh projection and coordinate transformation
   */
  bounds?: number[] | null;
}

interface MeshAttributes {
  /** Vertex positions as [x, y, z] coordinates */
  positions: Float32Array;
  
  /** Normal vectors for lighting calculations */
  normals?: Float32Array;
  
  /** Texture coordinates for UV mapping */
  texCoords?: Float32Array;
  
  /** Triangle indices for mesh connectivity */
  indices?: Uint32Array;
}

Mesh Quality Examples:

// High quality terrain (more triangles)
const highQuality = new TerrainLayer({
  id: 'high-quality',
  elevationData: 'https://tiles.example.com/{z}/{x}/{y}.png',
  meshMaxError: 0.5, // Very low error tolerance
  // Results in detailed mesh with many triangles
});

// Medium quality terrain (balanced)
const mediumQuality = new TerrainLayer({
  id: 'medium-quality', 
  elevationData: 'https://tiles.example.com/{z}/{x}/{y}.png',
  meshMaxError: 4.0, // Default error tolerance
  // Good balance of detail vs performance
});

// Low quality terrain (fewer triangles)
const lowQuality = new TerrainLayer({
  id: 'low-quality',
  elevationData: 'https://tiles.example.com/{z}/{x}/{y}.png', 
  meshMaxError: 20.0, // High error tolerance
  // Simplified mesh for better performance
});

Texture Mapping

Texture Overlay Support

Apply imagery textures over the terrain mesh for realistic visualization.

interface TextureProps {
  /** URL template for texture imagery */
  texture?: URLTemplate;
  
  /** Fallback color when texture is unavailable */
  color?: Color;
  
  /** Material properties affecting texture appearance */
  material?: Material | boolean;
}

interface Material {
  /** Ambient light coefficient (0-1) */
  ambient?: number;
  
  /** Diffuse light coefficient (0-1) */
  diffuse?: number;
  
  /** Specular shininess factor */
  shininess?: number;
  
  /** Specular highlight color */
  specularColor?: Color;
}

Texture Examples:

// Satellite imagery texture
const satelliteLayer = new TerrainLayer({
  id: 'satellite-terrain',
  elevationData: 'https://elevation.example.com/{z}/{x}/{y}.png',
  texture: 'https://satellite.example.com/{z}/{x}/{y}.jpg',
  
  material: {
    ambient: 0.4,    // Some ambient lighting
    diffuse: 0.8,    // Strong diffuse lighting
    shininess: 16,   // Moderate shininess
    specularColor: [255, 255, 255]
  }
});

// Color-coded elevation without texture
const coloredLayer = new TerrainLayer({
  id: 'colored-terrain',
  elevationData: 'https://elevation.example.com/{z}/{x}/{y}.png',
  // No texture prop - uses color instead
  color: [70, 120, 70], // Forest green
  
  material: true // Enable basic material lighting
});

// Multiple texture sources
const multiTextureLayer = new TerrainLayer({
  id: 'multi-texture',
  elevationData: 'https://elevation.example.com/{z}/{x}/{y}.png',
  
  // Use different textures based on zoom level
  texture: [
    'https://low-res.example.com/{z}/{x}/{y}.jpg',
    'https://high-res.example.com/{z}/{x}/{y}.jpg'
  ],
  
  color: [200, 200, 200], // Fallback gray
  material: true
});

Performance Optimization

Worker Processing

TerrainLayer uses web workers for mesh generation to avoid blocking the main thread.

interface WorkerProps {
  /**
   * URL to custom terrain worker bundle
   * Only needed for offline use or custom worker builds
   */
  workerUrl?: string;
}

Worker Configuration:

// Use custom worker for offline applications
const offlineLayer = new TerrainLayer({
  id: 'offline-terrain',
  elevationData: './local-tiles/{z}/{x}/{y}.png',
  workerUrl: './terrain-worker.js', // Local worker bundle
  meshMaxError: 4.0
});

// Default configuration uses CDN worker
const onlineLayer = new TerrainLayer({
  id: 'online-terrain',
  elevationData: 'https://tiles.example.com/{z}/{x}/{y}.png',
  // workerUrl not specified - uses default CDN worker
  meshMaxError: 4.0
});