Освещение в трёхмерной визуализации Deck.gl строится вокруг модели сцены, в которой геометрия слоёв реагирует на параметры источников света и материал поверхности. В отличие от двумерных карт, где визуальное восприятие определяется в основном цветом и прозрачностью, в 3D добавляется физически мотивированная модель взаимодействия света с поверхностями: диффузное отражение, зеркальные блики и затенение.
В основе системы освещения Deck.gl лежит объект
LightingEffect, который агрегирует набор источников света и
передаёт их в рендеринговый пайплайн слоёв. Каждый слой, поддерживающий
освещение (например, экструдированные полигоны, столбчатые диаграммы,
3D-сетки), вычисляет итоговый цвет пикселя с учётом:
Физическая модель упрощена, но близка к Blinn–Phong с возможными расширениями.
В Deck.gl используются несколько типов источников света, каждый из которых моделирует определённый сценарий освещения сцены.
Рассеянный свет, равномерно освещающий всю сцену без направления. Используется для предотвращения полного провала в тени.
import {AmbientLight} from '@deck.gl/core';
const ambientLight = new AmbientLight({
color: [255, 255, 255],
intensity: 0.5
});
Особенности:
Свет, имитирующий удалённый источник (например, солнце). Все лучи параллельны.
import {DirectionalLight} from '@deck.gl/core';
const directionalLight = new DirectionalLight({
color: [255, 255, 255],
intensity: 1.0,
direction: [-2, -3, -1]
});
Ключевые свойства:
Локальный источник света, излучающий во всех направлениях.
import {PointLight} from '@deck.gl/core';
const pointLight = new PointLight({
color: [255, 200, 180],
intensity: 2.0,
position: [0, 0, 1000]
});
Особенности:
Все источники объединяются через LightingEffect, который
передаётся в Deck как один из эффектов рендера.
import {Deck} from '@deck.gl/core';
import {LightingEffect} from '@deck.gl/core';
const lightingEffect = new LightingEffect({
ambientLight,
directionalLight,
pointLight
});
const deckgl = new Deck({
initialViewState: {
longitude: 0,
latitude: 0,
zoom: 2,
pitch: 45
},
controller: true,
layers: [],
effects: [lightingEffect]
});
Порядок и комбинация источников напрямую влияет на визуальную читаемость сцены: чрезмерный directional light делает сцену контрастной, а сильный ambient light «плоской».
Материал в Deck.gl описывает, как поверхность реагирует на свет. Он
задаётся через свойство material у поддерживающих
слоёв.
const material = {
ambient: 0.35,
diffuse: 0.6,
shininess: 32,
specularColor: [255, 255, 255]
};
Ambient (окружающее отражение) Определяет, сколько рассеянного света поглощает поверхность.
Diffuse (диффузное отражение) Основной вклад от направленного света. Формирует базовый цвет объекта.
Specular (зеркальные блики) Отвечает за яркие отражения источников света.
Shininess (гладкость) Контролирует размер и резкость блика: чем выше значение, тем «гладче» поверхность.
Поддержка освещения зависит от конкретного слоя. Наиболее часто используются:
PolygonLayer (включая экструзию)ColumnLayerGridCellLayerHexagonLayerScenegraphLayerПример с экструдированными полигонами:
import {PolygonLayer} from '@deck.gl/layers';
const layer = new PolygonLayer({
id: 'buildings',
data,
extruded: true,
wireframe: false,
getPolygon: d => d.coordinates,
getElevation: d => d.height,
material: {
ambient: 0.4,
diffuse: 0.6,
shininess: 10
}
});
При включённой экструзии нормали рассчитываются автоматически, что позволяет корректно реагировать на направление света.
Тени в Deck.gl основаны на принципе shadow mapping: сцена рендерится с точки зрения источника света, и полученная глубина используется для определения затемнённых областей.
При использовании направленного света возможно включение теней:
const directionalLight = new DirectionalLight({
color: [255, 255, 255],
intensity: 1.0,
direction: [-1, -2, -3],
shadow: true
});
Тени особенно заметны при работе с:
Deck.gl использует WebGL-шейдеры для расчёта освещения. Вершинный шейдер передаёт:
Фрагментный шейдер вычисляет итоговый цвет:
Упрощённая схема:
vec3 normal = normalize(vNormal);
vec3 lightDir = normalize(uLightDirection);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = diff * uLightColor;
vec3 ambient = uAmbientColor;
gl_FragColor = vec4(diffuse + ambient, 1.0);
Освещение в Deck.gl не фиксировано относительно экрана — оно вычисляется в мировом пространстве. Это означает:
Особенно важен параметр наклона камеры (pitch), который
усиливает или ослабляет читаемость рельефа.
Освещение и тени существенно влияют на производительность WebGL-приложений.
PointLightDirectionalLightПри неправильной настройке освещения возникают типичные проблемы:
Пересвет (overexposure) Слишком высокая интенсивность источников света.
Плоская сцена Чрезмерный ambient light без directional компоненты.
Шум в бликах Слишком высокий shininess на низкополигональной геометрии.
Ломанные тени Недостаточное разрешение shadow map или неправильная настройка bias.
Типичная конфигурация для городской 3D-карты:
const lightingEffect = new LightingEffect({
ambientLight: new AmbientLight({
color: [255, 255, 255],
intensity: 0.4
}),
directionalLight: new DirectionalLight({
color: [255, 255, 255],
intensity: 0.9,
direction: [-1, -1, -2],
shadow: true
})
});
Такой подход обеспечивает баланс между глубиной сцены и производительностью, сохраняя читаемость объектов при разных углах обзора.