LightingEffect

LightingEffect — механизм системы освещения в Deck.gl, предназначенный для моделирования взаимодействия источников света с трёхмерными объектами сцены. Эффект используется совместно с слоями, поддерживающими материалы и расчёт освещения, такими как PolygonLayer, SolidPolygonLayer, ColumnLayer, HexagonLayer, ScenegraphLayer, SimpleMeshLayer и рядом других.

Основная задача LightingEffect заключается в повышении визуальной реалистичности сцены. Без освещения большинство 3D-объектов отображаются плоскими и лишёнными глубины. При добавлении источников света появляются:

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

Архитектурно LightingEffect представляет собой объект эффекта, который передаётся в параметр effects экземпляра Deck.


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

Система освещения Deck.gl состоит из нескольких компонентов:

  1. Источники света.
  2. Материалы объектов.
  3. Эффекты сцены.
  4. Шейдеры слоёв.

Схема взаимодействия выглядит следующим образом:

Light Sources
      ↓
LightingEffect
      ↓
Layer Materials
      ↓
Shaders
      ↓
Rendered Scene

Каждый источник света описывает собственные характеристики:

  • положение;
  • цвет;
  • интенсивность;
  • направление;
  • свойства теней.

LightingEffect объединяет все источники света в единую систему и передаёт их в графический конвейер рендеринга.


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

Базовый пример создания эффекта освещения:

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

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

const lightingEffect = new LightingEffect({
  ambientLight
});

const deck = new Deck({
  initialViewState,
  controller: true,
  effects: [lightingEffect],
  layers: []
});

В данном примере создаётся один источник окружающего света и подключается к сцене.


AmbientLight

Общая характеристика

AmbientLight моделирует рассеянное освещение окружающей среды.

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

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

Создание AmbientLight

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

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

Параметры

color

Определяет цвет освещения.

color: [255, 255, 255]

Белый свет.

Пример тёплого освещения:

color: [255, 230, 180]

Пример холодного освещения:

color: [180, 220, 255]

intensity

Указывает силу света.

intensity: 1.0

Возможные значения:

0.2
0.5
1.0
2.0
5.0

Большие значения приводят к пересвету сцены.


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, 0, 0]

Свет справа.

direction: [-1, 0, 0]

Свет слева.

direction: [0, -1, 0]

Свет сверху.

direction: [0, 1, 0]

Свет снизу.

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

Солнечный свет под углом.


Настройка цвета

Закатное освещение:

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

Пасмурная погода:

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

PointLight

Назначение

PointLight моделирует точечный источник света.

Аналогами являются:

  • лампа;
  • фонарь;
  • прожектор без направленности;
  • светильник.

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


Создание PointLight

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

const pointLight = new PointLight({
  color: [255, 255, 255],
  intensity: 2.0,
  position: [-122.4, 37.8, 1000]
});

Параметр position

Координаты источника света:

position: [longitude, latitude, altitude]

Пример:

position: [
  -122.45,
  37.80,
  500
]

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

const redLight = new PointLight({
  color: [255, 0, 0],
  intensity: 2,
  position: [-122.4, 37.8, 1000]
});

const blueLight = new PointLight({
  color: [0, 0, 255],
  intensity: 2,
  position: [-122.42, 37.82, 1000]
});

Подобный подход используется для создания художественной подсветки объектов.


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

На практике почти всегда применяется несколько источников одновременно.

Пример:

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

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

const pointLight = new PointLight({
  color: [255, 240, 200],
  intensity: 2,
  position: [-122.4, 37.8, 1000]
});

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

Такая конфигурация обеспечивает:

  • базовую освещённость;
  • солнечное освещение;
  • локальную подсветку.

Материалы объектов

Освещение работает совместно с материалами.

Материал определяет реакцию поверхности на свет.

Пример:

material: {
  ambient: 0.4,
  diffuse: 0.6,
  shininess: 32,
  specularColor: [255, 255, 255]
}

ambient

Уровень реакции на окружающий свет.

ambient: 0.4

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


diffuse

Коэффициент рассеянного отражения.

diffuse: 0.6

Определяет основной вклад направленного света.


shininess

Степень блеска поверхности.

shininess: 32

Примеры:

shininess: 8

Матовая поверхность.

shininess: 64

Глянцевая поверхность.

shininess: 128

Полированная поверхность.


specularColor

Цвет зеркальных бликов.

specularColor: [255, 255, 255]

Золотистые блики:

specularColor: [255, 220, 120]

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

Пример для ColumnLayer:

new ColumnLayer({
  id: 'columns',
  data,
  diskResolution: 12,
  radius: 50,
  extruded: true,
  getPosition: d => d.position,
  getElevation: d => d.height,

  material: {
    ambient: 0.3,
    diffuse: 0.7,
    shininess: 64,
    specularColor: [255, 255, 255]
  }
});

Освещение в PolygonLayer

Экструзия должна быть включена:

new PolygonLayer({
  id: 'buildings',
  data,
  extruded: true,
  wireframe: false,
  filled: true,
  getElevation: d => d.height
});

Без экструзии освещение практически не влияет на внешний вид слоя, поскольку отсутствуют объёмные поверхности.


Освещение в ColumnLayer

ColumnLayer является одним из наиболее наглядных примеров применения освещения.

new ColumnLayer({
  id: 'population',
  data,
  extruded: true,
  radius: 100,
  getPosition: d => d.coordinates,
  getElevation: d => d.population
});

Боковые грани начинают реагировать на направление света, что делает столбцы визуально объёмными.


Освещение в HexagonLayer

Для трёхмерных гексагонов:

new HexagonLayer({
  id: 'hex',
  data,
  extruded: true,
  radius: 500,
  elevationScale: 20
});

Различия в освещении помогают лучше воспринимать перепады высоты между соседними ячейками.


Освещение в ScenegraphLayer

ScenegraphLayer активно использует систему освещения при отображении моделей GLTF.

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

В данном случае освещение влияет на:

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

Тени

shadows

Некоторые источники света поддерживают генерацию теней.

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

Тени существенно увеличивают реалистичность сцены.


Shadow Maps

Deck.gl использует технологию Shadow Maps.

Процесс состоит из двух этапов:

  1. Рендеринг глубины сцены со стороны источника света.
  2. Использование карты глубины для определения затенённых областей.

Схема:

Light
  ↓
Depth Map
  ↓
Shadow Calculation
  ↓
Final Rendering

Создание сцены с тенями

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

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

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

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

const deck = new Deck({
  effects: [lightingEffect],
  layers
});

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

Освещение оказывает влияние на быстродействие.

Наиболее затратными являются:

  • динамические тени;
  • большое количество источников света;
  • сложные GLTF-модели;
  • сцены с тысячами объектов.

По степени нагрузки:

AmbientLight        Низкая
DirectionalLight    Низкая
PointLight          Средняя
Shadows             Высокая

Практические рекомендации

Визуализация городов

Наиболее распространённая конфигурация:

AmbientLight
DirectionalLight

Она обеспечивает хорошее качество изображения при минимальных затратах ресурсов.


Архитектурные модели

Рекомендуемая комбинация:

AmbientLight
DirectionalLight
Shadow Mapping

Позволяет отчётливо отображать выступающие элементы зданий и особенности фасадов.


Промышленные 3D-сцены

Часто используется набор:

AmbientLight
DirectionalLight
PointLight

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


Визуализация транспорта

Для автомобилей, самолётов и кораблей особенно важны параметры материала:

material: {
  ambient: 0.25,
  diffuse: 0.6,
  shininess: 128,
  specularColor: [255, 255, 255]
}

Высокое значение shininess позволяет получить реалистичные отражающие поверхности.


Полный пример настройки LightingEffect

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

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

const sunLight = new DirectionalLight({
  color: [255, 255, 255],
  intensity: 1.5,
  direction: [-1, -3, -2],
  shadow: true
});

const pointLight = new PointLight({
  color: [255, 240, 200],
  intensity: 2,
  position: [-122.4, 37.8, 1000]
});

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

const deck = new Deck({
  initialViewState,
  controller: true,
  effects: [lightingEffect],
  layers: [
    new ColumnLayer({
      id: 'columns',
      data,
      extruded: true,
      getPosition: d => d.position,
      getElevation: d => d.height,

      material: {
        ambient: 0.3,
        diffuse: 0.6,
        shininess: 64,
        specularColor: [255, 255, 255]
      }
    })
  ]
});

Данная конфигурация объединяет все основные возможности LightingEffect: окружающее освещение, направленный солнечный свет, локальную подсветку, материалы поверхностей и генерацию теней для формирования реалистичной трёхмерной сцены в Deck.gl.