Terrain и рельеф местности

Поддержка трёхмерного рельефа в MapLibre GL JS основана на использовании цифровых моделей высот (DEM, Digital Elevation Model), которые интерпретируются на стороне клиента и преобразуются в геометрию WebGL-террейна. В отличие от классических тайловых слоёв, содержащих только цветовую информацию, DEM-текстуры кодируют высоту в каждом пикселе, что позволяет динамически деформировать поверхность карты.

Основная концепция рельефа заключается в том, что карта перестаёт быть плоской проекцией и становится трёхмерной сеткой, где каждая вершина соответствует значению высоты.


Источники данных высот (DEM)

Для работы рельефа используются специальные растровые тайлы высот:

  • Mapbox Terrain-RGB
  • MapTiler Terrain RGB
  • AWS Terrain tiles
  • кастомные DEM-тайлы в форматах Terrarium или Mapbox Encoding

Наиболее распространены два формата кодирования:

Mapbox Terrain-RGB

Высота кодируется в RGB-каналах:

[ height = (R ^2 + G + B) - 10000]

Terrarium format

Альтернативное кодирование:

[ height = (R + G + ) - 32768]

Такие форматы позволяют хранить высоту с высокой точностью в стандартных PNG-тайлах.


Подключение DEM-источника

В MapLibre GL JS DEM добавляется как raster-dem источник:

map.addSource('terrain-source', {
    type: 'raster-dem',
    url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
    tileSize: 512,
    encoding: 'mapbox'
});

Ключевые параметры:

  • type: raster-dem — тип источника высот
  • tileSize — размер тайла, часто 256 или 512
  • encoding — схема кодирования высот (mapbox или terrarium)

Включение рельефа через setTerrain

После подключения DEM-источника активируется рельеф:

map.setTerrain({
    source: 'terrain-source',
    exaggeration: 1.5
});

Параметры:

  • source — идентификатор DEM-источника
  • exaggeration — коэффициент вертикального усиления

Значение exaggeration влияет на визуальную выразительность:

  • 1.0 — реальная высота
  • 1.5–2.0 — умеренное усиление рельефа
  • >2.5 — стилизованный гипертрофированный рельеф

Внутреннее устройство террейна

Рельеф в MapLibre GL JS реализуется через WebGL-сетку, где:

  • тайлы DEM преобразуются в heightmap
  • каждая вершина сетки получает Z-координату
  • геометрия пересчитывается в реальном времени при изменении камеры

Система использует:

  • tile pyramid для LOD (level of detail)
  • frustum culling для отсечения невидимых тайлов
  • GPU-шейдеры для деформации поверхности

При изменении масштаба выбираются разные уровни детализации DEM, что предотвращает артефакты при наклоне камеры.


Сочетание рельефа и слоёв карты

Рельеф влияет на все растровые и векторные слои, которые размещаются поверх террейна. При этом слои автоматически «прилипают» к поверхности.

Пример базового стиля:

map.addLayer({
    id: 'hillshade',
    type: 'hillshade',
    source: 'terrain-source'
});

hillshade используется для визуального усиления рельефа за счёт имитации освещения.


Hillshade и визуализация освещения

Слой hillshade создаёт эффект теней, вычисляемых на основе наклона поверхности:

  • анализируется градиент высот
  • определяется направление освещения
  • вычисляется интенсивность света и тени
map.addLayer({
    id: 'terrain-shading',
    type: 'hillshade',
    source: 'terrain-source',
    paint: {
        'hillshade-exaggeration': 0.5,
        'hillshade-shadow-color': '#000000',
        'hillshade-highlight-color': '#ffffff'
    }
});

Ключевые свойства:

  • hillshade-exaggeration — усиление теней
  • shadow-color — цвет теней
  • highlight-color — цвет освещённых участков

Камера и работа с наклоном

Рельеф становится визуально значимым только при наклоне камеры:

map.easeTo({
    pitch: 60,
    bearing: -20,
    duration: 1000
});

Параметры камеры:

  • pitch — угол наклона
  • bearing — поворот карты
  • zoom — масштаб, влияющий на детализацию DEM

При увеличении pitch WebGL начинает активно интерполировать высоты, создавая ощущение объёма.


Фильтрация и качество DEM

Качество рельефа определяется несколькими факторами:

Разрешение DEM

  • 256×256 — базовый уровень
  • 512×512 — стандарт для современных карт
  • 1024×1024 — высокая детализация

Интерполяция

Используются методы:

  • bilinear filtering
  • trilinear filtering между уровнями zoom
  • GPU-based smoothing

Ограничения и особенности производительности

Рельеф является одной из наиболее ресурсоёмких функций MapLibre GL JS.

Основные факторы нагрузки:

  • количество DEM-тайлов в кадре
  • сложность геометрии terrain mesh
  • количество наклонённых слоёв
  • качество текстур высот

Оптимизация достигается через:

  • уменьшение tileSize
  • ограничение maxzoom для DEM
  • использование более грубого exaggeration на слабых устройствах

Комбинирование с 3D-слоями

Рельеф тесно взаимодействует с 3D-слоями:

  • fill-extrusion (3D здания)
  • custom layers (WebGL объекты)
  • линии маршрутов, привязанные к поверхности
map.addLayer({
    id: 'buildings-3d',
    type: 'fill-extrusion',
    source: 'composite',
    'source-layer': 'building',
    paint: {
        'fill-extrusion-height': ['get', 'height'],
        'fill-extrusion-base': ['get', 'min_height'],
        'fill-extrusion-opacity': 0.9
    }
});

Здания автоматически «садятся» на поверхность рельефа при активированном terrain.


Fog и атмосферные эффекты поверх рельефа

Современные стили MapLibre GL JS поддерживают атмосферные эффекты, усиливающие восприятие глубины:

map.setFog({
    color: 'rgb(220, 230, 240)',
    'horizon-blend': 0.2,
    'range': [1, 10]
});

Fog взаимодействует с террейном следующим образом:

  • дальние участки рельефа теряют контраст
  • усиливается ощущение глубины
  • маскируются границы тайлов

Практика работы с несколькими DEM-источниками

В сложных стилях возможно использование нескольких источников высот, например:

  • глобальный DEM низкого разрешения
  • локальные высокоточные DEM для горных регионов

Логика выбора осуществляется через приоритет источников в стиле.


Динамическое управление рельефом

Рельеф можно изменять во время работы карты:

map.setTerrain({
    source: 'terrain-source',
    exaggeration: 2.2
});

Изменение параметра exaggeration приводит к:

  • перерасчёту высот вершин
  • обновлению WebGL-шейдеров
  • перерисовке сцены без перезагрузки тайлов

Стилизация поверхности

Визуальный характер рельефа формируется сочетанием:

  • цветовой схемы базовой карты
  • hillshade слоя
  • fog и atmospheric scattering
  • освещения камеры

Часто применяются стили:

  • контрастный рельеф (горные районы)
  • сглаженный пастельный рельеф (городские карты)
  • минималистичный рельеф без теней

Геометрия террейна и WebGL pipeline

На уровне GPU террейн представляет собой сетку треугольников:

  • каждый тайл разбивается на mesh
  • вершины получают координаты (x, y, z)
  • z вычисляется из DEM текстуры

Vertex shader выполняет:

  • выбор высоты из texture lookup
  • преобразование в clip space
  • применение матриц камеры

Fragment shader отвечает за:

  • смешивание текстур
  • освещение
  • тени от hillshade

Поведение при разных масштабах

LOD (Level of Detail) управляет детализацией:

  • zoom < 5 — глобальные формы рельефа
  • zoom 5–10 — региональная детализация
  • zoom > 10 — локальные особенности поверхности

Переход между уровнями происходит плавно через морфинг тайлов.


Интеграция с пользовательскими слоями

Пользовательские WebGL-слои могут учитывать высоту рельефа через:

  • sampling DEM текстуры
  • использование terrain elevation API внутри shader
  • проекцию координат в 3D пространство

Это позволяет строить:

  • маршруты по поверхности
  • визуализацию потоков (реки, лавины)
  • геопространственные симуляции

Итоговая архитектура системы рельефа

Система Terrain в MapLibre GL JS состоит из нескольких уровней:

  • источник высот (raster-dem)
  • декодирование DEM
  • генерация mesh
  • WebGL рендеринг
  • постобработка (hillshade, fog)
  • интеграция с векторными и 3D слоями

Эта архитектура обеспечивает непрерывную трансформацию плоской карты в интерактивную трёхмерную поверхность с динамической геометрией и адаптивной детализацией.