Directional освещение

Освещение играет важную роль при визуализации трёхмерных объектов на карте. Без корректной настройки источников света объекты выглядят плоскими, теряют глубину и становятся сложнее для восприятия. Одним из наиболее важных типов освещения в Deck.gl является Directional Light — направленный источник света, имитирующий удалённый объект наподобие Солнца.

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

Наиболее часто Directional Light применяется для:

  • отображения зданий в PolygonLayer;
  • освещения объектов в ScenegraphLayer;
  • визуализации 3D-моделей;
  • формирования реалистичных теней;
  • повышения читаемости рельефа и экструзий.

Архитектура системы освещения Deck.gl

Система освещения реализована через набор специальных классов из пакета:

import {
  AmbientLight,
  DirectionalLight,
  LightingEffect
} from '@deck.gl/core';

Основные типы освещения:

Тип Назначение
AmbientLight Равномерное фоновое освещение
DirectionalLight Направленный свет
PointLight Точечный источник света
CameraLight Свет от камеры

В большинстве проектов используется комбинация:

AmbientLight + DirectionalLight

Такое сочетание обеспечивает хорошую детализацию поверхностей без чрезмерного затемнения.


Класс DirectionalLight

Создание направленного источника света выполняется через класс DirectionalLight.

Базовый пример:

import {DirectionalLight} from '@deck.gl/core';

const sunlight = new DirectionalLight({
  color: [255, 255, 255],
  intensity: 1.0,
  direction: [-1, -3, -1]
});

Параметры конструктора определяют свойства света и его влияние на сцену.


Параметр direction

Самая важная характеристика направленного света — направление лучей.

Пример:

direction: [-1, -3, -1]

Вектор показывает направление распространения света.

Компоненты:

[x, y, z]

где:

  • x — направление по оси восток-запад;
  • y — направление по оси север-юг;
  • z — направление по вертикали.

Пример освещения сверху:

direction: [0, 0, -1]

Свет падает строго вниз.

Освещение под углом:

direction: [-1, -2, -1]

Освещение почти горизонтально:

direction: [-5, -1, -0.2]

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


Нормализация направления

Длина вектора направления не имеет значения.

Следующие варианты эквивалентны:

direction: [-1, -1, -1]
direction: [-10, -10, -10]
direction: [-100, -100, -100]

Внутри движка выполняется нормализация:

v = v / |v|

Поэтому важно только соотношение координат.


Параметр color

Определяет цвет света.

Белый источник:

color: [255, 255, 255]

Тёплое солнечное освещение:

color: [255, 240, 210]

Закатный свет:

color: [255, 180, 120]

Холодное освещение:

color: [180, 220, 255]

Пример:

const sunlight = new DirectionalLight({
  color: [255, 230, 180],
  intensity: 1.2,
  direction: [-1, -2, -1]
});

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


Параметр intensity

Управляет яркостью источника света.

Пример:

intensity: 1.0

Допустимы любые положительные значения.

Слабый свет:

intensity: 0.3

Средний:

intensity: 1.0

Яркий:

intensity: 2.5

Очень яркий:

intensity: 5.0

Пример:

const sunlight = new DirectionalLight({
  direction: [-1, -3, -1],
  intensity: 2.0
});

Слишком большие значения могут приводить к пересвету объектов.


Создание LightingEffect

Отдельный источник света не влияет на сцену автоматически.

Сначала создаётся объект эффекта:

const lightingEffect = new LightingEffect({
  sunlight
});

Затем он передаётся в Deck:

new Deck({
  effects: [lightingEffect]
});

Полный пример:

const sunlight = new DirectionalLight({
  color: [255, 255, 255],
  intensity: 1.0,
  direction: [-1, -3, -1]
});

const lightingEffect = new LightingEffect({
  sunlight
});

new Deck({
  effects: [lightingEffect]
});

Комбинирование с AmbientLight

Использование только направленного света редко даёт хороший результат.

Часть объектов оказывается полностью чёрной.

Поэтому обычно добавляется фоновое освещение:

const ambientLight = new AmbientLight({
  color: [255, 255, 255],
  intensity: 0.4
});

И направленный свет:

const sunlight = new DirectionalLight({
  color: [255, 255, 255],
  intensity: 1.0,
  direction: [-1, -3, -1]
});

Создание эффекта:

const lightingEffect = new LightingEffect({
  ambientLight,
  sunlight
});

Такая схема наиболее распространена в производственных проектах.


Освещение экструзий PolygonLayer

Directional Light особенно важен при использовании экструзий.

Пример слоя:

new PolygonLayer({
  id: 'buildings',
  data,
  extruded: true,
  getElevation: d => d.height,
  getFillColor: [80, 120, 200]
});

Без освещения:

  • стены выглядят одинаково;
  • сложно определить форму здания;
  • отсутствует ощущение объёма.

С Directional Light:

  • появляются светлые и тёмные грани;
  • хорошо видны углы;
  • возрастает реалистичность сцены.

Влияние направления света на здания

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

Свет сверху:

direction: [0, 0, -1]

Результат:

  • минимальная выраженность теней;
  • одинаковое освещение фасадов.

Свет сбоку:

direction: [-1, -1, -0.5]

Результат:

  • ярко выраженные контуры;
  • заметный объём зданий.

Низкий угол:

direction: [-2, -4, -0.2]

Результат:

  • длинные тени;
  • сильный контраст;
  • эффект закатного освещения.

Несколько направленных источников света

Deck.gl позволяет создавать несколько источников.

Пример:

const sun = new DirectionalLight({
  direction: [-1, -2, -1],
  intensity: 1
});

const fill = new DirectionalLight({
  direction: [1, 1, -0.5],
  intensity: 0.3
});

Подключение:

const lightingEffect = new LightingEffect({
  sun,
  fill
});

Подобная схема широко применяется в компьютерной графике.

Первый источник формирует основное освещение.

Второй источник смягчает слишком тёмные участки.


Работа с тенями

Directional Light поддерживает генерацию теней.

Пример:

const sunlight = new DirectionalLight({
  direction: [-1, -3, -1],
  intensity: 1
});

При использовании механизма shadow mapping свет становится источником теней для объектов сцены.

Тени позволяют:

  • определять взаимное расположение объектов;
  • усиливать ощущение глубины;
  • повышать реалистичность визуализации.

Shadow-параметры Directional Light

Для работы теней используются дополнительные настройки.

Пример:

const sunlight = new DirectionalLight({
  direction: [-1, -3, -1],
  intensity: 1,
  shadow: true
});

После включения:

shadow: true

источник начинает участвовать в расчёте теневых карт.


Использование солнца как Directional Light

Наиболее естественная модель освещения карты выглядит следующим образом:

const sunlight = new DirectionalLight({
  color: [255, 245, 230],
  intensity: 1.2,
  direction: [-1, -3, -1]
});

Такая конфигурация напоминает дневное солнце.

Для заката:

const sunset = new DirectionalLight({
  color: [255, 180, 120],
  intensity: 0.8,
  direction: [-2, -4, -0.2]
});

Для пасмурной погоды:

const cloudy = new DirectionalLight({
  color: [220, 230, 255],
  intensity: 0.6,
  direction: [-1, -1, -1]
});

Освещение ScenegraphLayer

Трёхмерные модели особенно сильно зависят от настроек освещения.

Пример:

new ScenegraphLayer({
  id: 'cars',
  data,
  scenegraph: '/models/car.glb',
  getPosition: d => d.coordinates
});

При отсутствии Directional Light:

  • модели выглядят плоскими;
  • материалы теряют детализацию;
  • плохо различаются грани.

С корректным освещением:

  • видны поверхности кузова;
  • заметны изгибы геометрии;
  • лучше отображаются материалы.

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

Сам расчёт направленного света требует относительно небольших ресурсов.

Основные затраты связаны с:

  • большим количеством вершин;
  • вычислением теней;
  • высоким разрешением shadow maps.

Обычное освещение:

DirectionalLight + AmbientLight

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

Наиболее затратной операцией является:

shadow: true

особенно при большом количестве объектов на сцене.


Практическая конфигурация для городских сцен

Часто используется следующая схема:

const ambientLight = new AmbientLight({
  intensity: 0.35
});

const sunlight = new DirectionalLight({
  color: [255, 245, 230],
  intensity: 1.2,
  direction: [-1, -3, -1]
});

const lightingEffect = new LightingEffect({
  ambientLight,
  sunlight
});

Особенности такой конфигурации:

  • хорошо читаются фасады зданий;
  • отсутствуют полностью чёрные поверхности;
  • сохраняется реалистичный объём;
  • обеспечивается высокая производительность;
  • настройки подходят для большинства картографических 3D-сцен без дополнительной корректировки.