PointCloudLayer

Deck.gl предоставляет слой PointCloudLayer для визуализации больших облаков точек, получаемых из LiDAR-сканирования, фотограмметрии, 3D-сенсоров и геопространственных источников. Слой ориентирован на высокопроизводительный рендеринг миллионов точек через WebGL, минимизируя CPU-накладные расходы за счёт батчинга и использования атрибутов вершин.

PointCloudLayer построен на базе WebGL point primitives, где каждая точка представляется отдельной вершиной с набором атрибутов: позиция, цвет, размер и дополнительные пользовательские данные. В отличие от более сложных 3D-слоёв (например, mesh или scatterplot с геометрией), здесь отсутствует геометрическая интерполяция — рендеринг выполняется напрямую через gl.POINTS.

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

Структура входных данных

PointCloudLayer принимает массив объектов, где каждый элемент описывает одну точку или группу точек. Основная конфигурация извлечения атрибутов задаётся через accessor-функции:

  • getPosition — координаты точки в пространстве
  • getColor — цвет точки
  • getNormal — нормаль (опционально, используется для освещения)
  • getPointSize — размер точки

Типичный формат данных:

const data = [
  { position: [30.5, 59.9, 120.0], color: [255, 0, 0], size: 2 },
  { position: [30.6, 59.91, 118.0], color: [0, 255, 0], size: 3 }
];

Для больших массивов предпочтительно использовать бинарные форматы (TypedArray, ArrayBuffer), чтобы минимизировать накладные расходы парсинга.

Базовая инициализация слоя

PointCloudLayer создаётся как часть композиции слоёв внутри Deck.gl приложения:

import {Deck} from '@deck.gl/core';
import {PointCloudLayer} from '@deck.gl/layers';

const layer = new PointCloudLayer({
  id: 'point-cloud',
  data,
  getPosition: d => d.position,
  getColor: d => d.color,
  getPointSize: d => d.size,
  sizeUnits: 'pixels',
  pointSizeMinPixels: 1,
  pointSizeMaxPixels: 10
});

const deck = new Deck({
  initialViewState: {
    longitude: 30.5,
    latitude: 59.9,
    zoom: 10,
    pitch: 45,
    bearing: 0
  },
  controller: true,
  layers: [layer]
});

Координатные системы и масштабирование

PointCloudLayer поддерживает различные системы координат, включая:

  • COORDINATE_SYSTEM.LNGLAT
  • COORDINATE_SYSTEM.CARTESIAN
  • COORDINATE_SYSTEM.METER_OFFSETS

Выбор системы влияет на интерпретацию координат и точность визуализации. Для геопространственных данных чаще используется LNGLAT, где позиция задаётся как [долгота, широта, высота].

Размер точек может быть задан в:

  • pixels — фиксированный размер на экране
  • meters — реальный масштаб в пространстве

При работе с масштабированием важно учитывать перспективную деформацию: точки, заданные в метрах, будут уменьшаться при удалении камеры.

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

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

  1. GPU batching — передача атрибутов в виде буферов WebGL
  2. Attribute updater — обновление только изменённых данных
  3. Level-of-detail (LOD) — упрощение визуализации при отдалении камеры
  4. Frustum culling — исключение невидимых точек

Наиболее критичным фактором производительности является размер буферов. Рекомендуется избегать частых пересозданий data-массива и использовать мемоизацию атрибутов.

Работа с цветом и освещением

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

getNormal: d => d.normal

Это позволяет применять базовые модели освещения (Lambert shading), что особенно полезно для 3D-сканов поверхностей.

Цветовая интерполяция выполняется на GPU, что снижает нагрузку на CPU при динамических сценах.

Обработка больших LiDAR-наборов

При работе с LiDAR-данными типичная структура включает десятки миллионов точек. В таких случаях применяется стратегия:

  • разбиение на тайлы
  • загрузка по мере приближения камеры
  • использование compressed binary форматов (LAS/LAZ → preprocessed ArrayBuffer)

Пример адаптированного загрузчика:

async function loadTile(url) {
  const response = await fetch(url);
  const buffer = await response.arrayBuffer();
  return parsePointCloud(buffer);
}

Каждый тайл передаётся в PointCloudLayer как отдельный сегмент данных.

Управление размером точек

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

  • pointSizeMinPixels — минимальный размер
  • pointSizeMaxPixels — максимальный размер
  • sizeUnits — единицы измерения

Пример конфигурации:

new PointCloudLayer({
  pointSizeMinPixels: 0.5,
  pointSizeMaxPixels: 8,
  sizeUnits: 'pixels'
});

При работе с плотными облаками уменьшение максимального размера снижает визуальный шум и повышает читаемость структуры.

Интеграция с 3D сценой

PointCloudLayer часто используется совместно с другими слоями Deck.gl, такими как TerrainLayer или ScatterplotLayer. В таких композициях важно учитывать порядок рендеринга и прозрачность.

При включённой прозрачности (alpha blending) порядок отрисовки влияет на итоговую визуализацию, поэтому рекомендуется сортировка по глубине или использование depth testing.

Атрибутная модель и шейдеры

На уровне WebGL слой использует кастомные vertex и fragment shaders. Основные атрибуты:

  • POSITION
  • COLOR
  • POINT_SIZE

Vertex shader преобразует координаты в clip-space, а fragment shader формирует пиксельную форму точки, обычно в виде круга с мягкими краями (distance field или discard-based shaping).

Фрагмент упрощённой логики:

void main(void) {
  vec2 coord = gl_PointCoord - vec2(0.5);
  if (length(coord) > 0.5) discard;
  gl_FragColor = vec4(vColor, 1.0);
}

Использование в геоаналитике

PointCloudLayer применяется для:

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

Особенно эффективно сочетание с временными рядами, где цвет или размер точки изменяется в зависимости от параметра времени или интенсивности сигнала.

Обработка интерактивности

Слой поддерживает picking — определение точки под курсором. Это реализуется через уникальные идентификаторы объектов и framebuffer selection pass.

Пример включения:

new PointCloudLayer({
  pickable: true,
  onClick: info => console.log(info.object)
});

При высокой плотности данных рекомендуется ограничивать pick radius или использовать spatial indexing для ускорения поиска.