Освещение и тени

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

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


Структура объекта light

Объект light задаётся внутри style specification:

{
  "version": 8,
  "lights": {
    "ambient-light": {
      "type": "ambient",
      "color": "#ffffff",
      "intensity": 0.3
    },
    "directional-light": {
      "type": "directional",
      "color": "#ffffff",
      "intensity": 0.8,
      "direction": [180, 45]
    }
  }
}

В Mapbox GL JS чаще используется динамическое управление освещением через API:

map.setLight({
  anchor: "map",
  color: "white",
  intensity: 0.5,
  position: [1.15, 210, 30]
});

Типы источников освещения

Ambient light (рассеянный свет)

Рассеянный свет задаёт базовую освещённость сцены. Он не имеет направления и равномерно влияет на все объекты.

Характеристики:

  • отсутствует направление
  • равномерное освещение
  • используется как “фон света”

Основное назначение — предотвращение полной темноты на неосвещённых поверхностях.


Directional light (направленный свет)

Направленный свет имитирует солнце. Все лучи считаются параллельными, а освещение зависит от ориентации поверхностей.

Параметры:

  • intensity — сила света
  • color — цвет источника
  • position — сферические координаты источника

Пример:

map.setLight({
  color: "#ffffff",
  intensity: 0.9,
  position: [1.2, 180, 45]
});

Где:

  • первый элемент — азимут (0–360°)
  • второй — угол высоты (0–180°)
  • третий — интенсивность (в некоторых реализациях интерпретируется как высота источника)

Система координат освещения

Mapbox GL JS использует сферическую систему координат:

  • azimuthal angle — горизонтальное направление света
  • polar angle — вертикальный угол над горизонтом

Это позволяет имитировать движение солнца в течение дня.


Динамическое освещение и анимация времени суток

Освещение часто используется для симуляции суточного цикла.

Пример плавного изменения положения источника света:

function setTimeOfDay(hour) {
  const azimuth = (hour / 24) * 360;
  const elevation = hour < 12
    ? (hour / 12) * 60
    : ((24 - hour) / 12) * 60;

  map.setLight({
    anchor: "map",
    position: [azimuth, elevation, 1.2]
  });
}

При анимации важно учитывать:

  • сглаживание переходов
  • непрерывность азимута (обход 360°)
  • адаптацию интенсивности

Освещение 3D-зданий (fill-extrusion)

Слой fill-extrusion является основным потребителем системы освещения.

map.addLayer({
  id: "buildings",
  type: "fill-extrusion",
  source: "composite",
  "source-layer": "building",
  paint: {
    "fill-extrusion-color": "#aaa",
    "fill-extrusion-height": ["get", "height"],
    "fill-extrusion-base": ["get", "min_height"],
    "fill-extrusion-opacity": 0.9
  }
});

Освещение влияет на:

  • яркость граней
  • контраст боковых поверхностей
  • затенение внутренних углов

Каждая грань здания вычисляет нормаль, после чего применяется скалярное произведение с направлением света.


Математика освещения в WebGL контексте

В основе лежит классическая модель Lambert:

[ I = I_0 (0, )]

где:

  • ( ) — нормаль поверхности
  • ( ) — направление света
  • ( I_0 ) — интенсивность источника

В Mapbox GL JS эта модель упрощена, но принцип остаётся тем же: угол между поверхностью и светом определяет яркость.


Влияние освещения на рельеф (terrain)

При использовании terrain (DEM-данных) освещение становится критическим для восприятия глубины.

Рельеф может быть дополнительно усилен слоями типа hillshade:

map.addLayer({
  id: "hillshade",
  type: "hillshade",
  source: "dem",
  paint: {
    "hillshade-exaggeration": 0.5,
    "hillshade-shadow-color": "#000000",
    "hillshade-highlight-color": "#ffffff"
  }
});

Связь освещения и теней

В Mapbox GL JS нет полноценной физической модели теней (shadow mapping), но визуальный эффект достигается комбинацией:

  • направленного света
  • градиентов shading
  • геометрии объектов
  • hillshade-слоёв

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


Управление интенсивностью света

Интенсивность влияет на общую экспозицию сцены:

map.setLight({
  intensity: 0.2
});

Высокие значения:

  • увеличивают контраст
  • уменьшают читаемость рельефа в ярких сценах

Низкие значения:

  • создают мягкое освещение
  • повышают видимость деталей в тенях

Цветовая температура и художественное освещение

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

  • холодный свет (синий оттенок) — ночные сцены
  • тёплый свет (жёлто-оранжевый) — закат
  • нейтральный белый — дневное освещение

Пример:

map.setLight({
  color: "#ffcc88",
  intensity: 0.7
});

Освещение и слой sky

Слой sky усиливает восприятие освещения за счёт окружения сцены.

map.addLayer({
  id: "sky",
  type: "sky",
  paint: {
    "sky-type": "atmosphere",
    "sky-atmosphere-sun": [0.0, 0.0],
    "sky-atmosphere-sun-intensity": 10
  }
});

Sky слой взаимодействует с направлением света, создавая визуальную связку между небом и поверхностью карты.


Производительность освещения

Освещение в Mapbox GL JS оптимизировано для GPU:

  • вычисления выполняются в вершинных и фрагментных шейдерах
  • минимизируются CPU-операции
  • параметры света передаются как uniform variables

При сложных сценах важно учитывать:

  • количество 3D-слоёв
  • частоту обновления light
  • стоимость перерисовки кадра

Практика построения реалистичной сцены

Реалистичная сцена формируется комбинацией:

  • направленного света с низким углом (утро/вечер)
  • умеренной интенсивности
  • нейтрального ambient освещения
  • рельефа с hillshade
  • 3D-зданий с extrusions
  • атмосферы через sky layer

Типичная конфигурация:

map.setLight({
  anchor: "map",
  color: "#ffffff",
  intensity: 0.6,
  position: [210, 45, 1.1]
});

Ограничения системы освещения

Система освещения Mapbox GL JS имеет ряд упрощений:

  • отсутствует полноценное глобальное освещение
  • нет динамических теней от объектов
  • нет отражений между объектами
  • ограниченная модель материалов

Это компенсируется скоростью рендеринга и стабильностью работы в браузере.


Взаимодействие освещения с стилями карты

Освещение тесно связано с визуальной темой стиля:

  • светлые стили требуют меньшей интенсивности
  • тёмные стили используют усиленный directional light
  • кастомные стили часто фиксируют light для консистентности

Изменение light может полностью менять восприятие одной и той же карты без изменения геометрии или данных.