Настройка теней

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

В Deck.gl поддержка теней реализована через систему освещения. Для формирования теней используются специальные источники света, способные генерировать карту глубины (shadow map), которая затем применяется во время рендеринга сцены.

Тени доступны только для слоёв, поддерживающих освещение и материалы.


Принцип работы теней

Механизм теней в Deck.gl основан на классическом подходе Shadow Mapping:

  1. Источник света создаёт карту глубины сцены.
  2. Для каждого пикселя определяется, находится ли он на пути света.
  3. Если пиксель перекрывается другим объектом относительно источника света, он считается затенённым.
  4. Освещённые и затенённые участки отображаются с разной яркостью.

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

Источник света
       |
       v
  Карта глубины
       |
       v
 Проверка видимости
       |
       v
 Отрисовка теней

Этот подход обеспечивает высокую производительность даже при большом количестве объектов.


Требования для работы теней

Для корректного отображения теней необходимо выполнение нескольких условий:

Использование освещения

Тени работают только совместно с системой LightingEffect.

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

Наличие источника света

Источник света должен поддерживать создание теней.

Наиболее распространённый вариант:

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

или

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

Поддержка материалов слоем

Слой должен использовать параметры материала.

Например:

material: true

или объект Material.


Источники света и тени

AmbientLight

Окружающее освещение равномерно освещает всю сцену.

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

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

Особенности:

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

DirectionalLight

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

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

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

Преимущества:

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

Для создания теней необходимо активировать соответствующую возможность.

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

SunLight

SunLight является специализированным вариантом направленного света.

Он рассчитывает положение солнца по времени суток и координатам.

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

const sunlight = new SunLight({
  timestamp: Date.UTC(
    2025,
    5,
    15,
    12
  )
});

Особенности:

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

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

После настройки источников света необходимо создать объект эффекта освещения.

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

Подключение эффекта:

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

Если используется несколько источников света:

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

Включение теней в LightingEffect

Для генерации теней необходимо указать список источников света, которые должны участвовать в построении shadow map.

Пример настройки:

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

lightingEffect.shadowColor = [0, 0, 0, 180];

Параметр shadowColor задаёт цвет и прозрачность теней.

Более тёмные тени:

lightingEffect.shadowColor = [
  0,
  0,
  0,
  220
];

Мягкие тени:

lightingEffect.shadowColor = [
  0,
  0,
  0,
  100
];

Настройка материалов

Качество отображения теней во многом зависит от параметров материала.

Пример материала:

const material = {
  ambient: 0.3,
  diffuse: 0.7,
  shininess: 32,
  specularColor: [255, 255, 255]
};

Использование:

new ColumnLayer({
  id: 'columns',
  data,
  material
});

Назначение параметров:

Параметр Описание
ambient Влияние окружающего света
diffuse Рассеянное освещение
shininess Размер блика
specularColor Цвет отражения

Тени в ColumnLayer

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

new ColumnLayer({
  id: 'buildings',
  data,
  extruded: true,
  radius: 100,
  elevationScale: 10,
  material
});

Тени особенно полезны при визуализации:

  • плотности населения;
  • статистических данных;
  • тепловых карт в виде колонок;
  • финансовых показателей.

Тени в GeoJsonLayer

При использовании экструдированных полигонов тени позволяют создавать полноценные трёхмерные карты.

new GeoJsonLayer({
  id: 'geojson',
  data,
  extruded: true,
  filled: true,
  material,
  getElevation: f => f.properties.height
});

Применение:

  • здания;
  • кварталы;
  • административные районы;
  • промышленные зоны.

Тени в PolygonLayer

Для пользовательских полигонов поддержка теней включается автоматически при использовании экструзии.

new PolygonLayer({
  id: 'polygons',
  data,
  extruded: true,
  material,
  getElevation: d => d.height
});

Чем выше объект, тем более заметной становится его тень.


Тени в ScenegraphLayer

Трёхмерные модели особенно выигрывают от использования теней.

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

Преимущества:

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

Настройка интенсивности освещения

Изменяя интенсивность света, можно управлять выраженностью теней.

Слабый свет:

const sunlight = new SunLight({
  timestamp: Date.now(),
  intensity: 0.5
});

Сильный свет:

const sunlight = new SunLight({
  timestamp: Date.now(),
  intensity: 3
});

Повышение интенсивности обычно делает границы теней более заметными.


Управление направлением теней

Для DirectionalLight направление определяется вектором.

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

Тень будет направлена противоположно источнику света.

Примеры:

direction: [1, -1, 0]

Свет справа.

direction: [-1, -1, 0]

Свет слева.

direction: [0, -1, -1]

Свет спереди.


Реалистичное солнечное освещение

Для геопространственных приложений рекомендуется использовать SunLight.

Пример:

const sunlight = new SunLight({
  timestamp: Date.UTC(
    2025,
    11,
    21,
    8,
    0,
    0
  )
});

Утреннее солнце создаёт длинные тени.

Полуденное солнце:

const sunlight = new SunLight({
  timestamp: Date.UTC(
    2025,
    11,
    21,
    12,
    0,
    0
  )
});

Тени становятся значительно короче.


Производительность при работе с тенями

Генерация теней является одной из наиболее затратных операций в графическом конвейере.

На производительность влияют:

  • количество объектов;
  • размер shadow map;
  • число источников света;
  • сложность геометрии;
  • разрешение экрана.

Особенно затратны сцены с тысячами экструдированных объектов.


Оптимизация теней

Ограничение количества источников света

В большинстве проектов достаточно одного источника света, генерирующего тени.

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

Упрощение геометрии

Следует избегать чрезмерно детализированных моделей.

Например:

getElevation: d => d.height

часто оказывается эффективнее сложных трёхмерных моделей для отображения высоты объектов.


Использование LOD

Level of Detail позволяет снижать детализацию удалённых объектов.

Преимущества:

  • уменьшение нагрузки на GPU;
  • ускорение генерации теней;
  • повышение частоты кадров.

Ограничение области отображения

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

Это уменьшает количество объектов, участвующих в расчёте теней.


Отладка теней

Распространённые причины отсутствия теней:

Не подключён LightingEffect

effects: [lightingEffect]

Отсутствует источник света

new LightingEffect({
  ambientLight
});

В таком случае тени не будут создаваться.


Слой не поддерживает материалы

Некоторые слои отображаются без освещения и не участвуют в системе теней.

Необходимо использовать слои с поддержкой освещения, например:

  • GeoJsonLayer (extruded);
  • ColumnLayer;
  • PolygonLayer;
  • ScenegraphLayer;
  • SimpleMeshLayer.

Объекты не имеют высоты

Если экструзия отключена:

extruded: false

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


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

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

import {GeoJsonLayer} from '@deck.gl/layers';

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

const sunlight = new SunLight({
  timestamp: Date.now(),
  intensity: 2
});

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

lightingEffect.shadowColor = [
  0,
  0,
  0,
  160
];

const material = {
  ambient: 0.3,
  diffuse: 0.7,
  shininess: 32,
  specularColor: [255, 255, 255]
};

const layer = new GeoJsonLayer({
  id: 'buildings',
  data: buildings,
  extruded: true,
  filled: true,
  material,
  getElevation: f => f.properties.height
});

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

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