Point Cloud

Point Cloud (облако точек) представляет собой набор пространственных точек, каждая из которых содержит координаты и дополнительные атрибуты: цвет, интенсивность отражённого сигнала, классификацию, нормали поверхности и другие данные. Облака точек широко применяются в геодезии, картографии, строительстве, горнодобывающей промышленности, городском планировании и системах цифровых двойников.

В экосистеме CesiumJS облака точек чаще всего используются для визуализации данных лазерного сканирования (LiDAR), фотограмметрии и результатов трёхмерной съёмки территорий. Благодаря поддержке стандарта 3D Tiles, движок способен эффективно отображать миллиарды точек, автоматически подгружая только необходимые данные.

Основные преимущества использования Point Cloud в CesiumJS:

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

Архитектура облаков точек в CesiumJS

В большинстве случаев облака точек загружаются через формат 3D Tiles Point Cloud.

Структура обычно состоит из:

tileset.json
├── tile_0.pnts
├── tile_1.pnts
├── tile_2.pnts
└── ...

Файл tileset.json содержит описание иерархии тайлов, а файлы .pnts хранят непосредственно точки.

Cesium использует механизм:

  1. Определение положения камеры.
  2. Вычисление видимых тайлов.
  3. Подгрузка необходимых сегментов.
  4. Отображение точек на GPU.
  5. Выгрузка невидимых данных из памяти.

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


Загрузка Point Cloud через Cesium3DTileset

Наиболее распространённый способ отображения облака точек выглядит следующим образом:

const viewer = new Cesium.Viewer("cesiumContainer");

const pointCloud = await Cesium.Cesium3DTileset.fromUrl(
    "./tileset/tileset.json"
);

viewer.scene.primitives.add(pointCloud);

await viewer.zoomTo(pointCloud);

После загрузки Cesium автоматически определяет тип содержимого тайлов. Если внутри находятся данные Point Cloud, будет использован соответствующий рендерер.


Формат .pnts

Файлы Point Cloud в 3D Tiles используют расширение:

.pnts

Каждая точка может содержать:

Атрибут Описание
POSITION Координаты точки
RGB Цвет
RGBA Цвет и прозрачность
NORMAL Нормаль
INTENSITY Интенсивность сигнала LiDAR
CLASSIFICATION Класс объекта
BATCH_ID Идентификатор группы

Например, точка может описываться следующими данными:

X: 412345.22
Y: 5842231.11
Z: 112.45
R: 120
G: 180
B: 210
Intensity: 86
Classification: Building

Позиционирование облака точек

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

Однако иногда требуется дополнительное преобразование.

Смещение по координатам

const tileset = await Cesium.Cesium3DTileset.fromUrl(
    "./tileset/tileset.json"
);

viewer.scene.primitives.add(tileset);

const translation = Cesium.Cartesian3.fromElements(
    10,
    20,
    5
);

tileset.modelMatrix = Cesium.Matrix4.fromTranslation(
    translation
);

Поворот облака точек

const heading = Cesium.Math.toRadians(90);

const matrix =
    Cesium.Transforms.headingPitchRollToFixedFrame(
        Cesium.Cartesian3.fromDegrees(
            37.62,
            55.75,
            0
        ),
        new Cesium.HeadingPitchRoll(
            heading,
            0,
            0
        )
    );

tileset.modelMatrix = matrix;

Настройка размера точек

Для облаков точек важным параметром является размер отображаемых элементов.

pointCloudShading

Cesium предоставляет объект:

Cesium.PointCloudShading

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

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        attenuation: true
    });

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

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        attenuation: true,
        geometricErrorScale: 2.0
    });

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


Point Cloud Shading

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

Пример:

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        attenuation: true,
        eyeDomeLighting: true
    });

Eye Dome Lighting

Eye Dome Lighting (EDL) создаёт псевдо-тени между соседними точками.

Без EDL:

Объекты выглядят плоскими.

С EDL:

Появляется визуальная глубина.
Улучшается читаемость рельефа.
Повышается различимость мелких деталей.

Настройка:

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        eyeDomeLighting: true,
        eyeDomeLightingStrength: 1.5,
        eyeDomeLightingRadius: 2.0
    });

Стилизация Point Cloud

Cesium позволяет менять внешний вид точек через систему стилей.

Создание стиля:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: "color('yellow')"
});

Все точки будут окрашены в жёлтый цвет.


Цвет по высоте

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${POSITION}[2] > 100", "color('red')"],
            ["${POSITION}[2] > 50", "color('orange')"],
            ["true", "color('green')"]
        ]
    }
});

Здесь используется координата Z.


Цвет по интенсивности LiDAR

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${Intensity} > 200", "color('white')"],
            ["${Intensity} > 100", "color('gray')"],
            ["true", "color('black')"]
        ]
    }
});

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


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

Многие LiDAR-данные содержат поле классификации.

Типичные значения:

Код Объект
1 Не классифицировано
2 Земля
3 Растительность
6 Здание
9 Вода

Стилизация по классу:

tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
        conditions: [
            ["${Classification} === 2", "color('brown')"],
            ["${Classification} === 3", "color('green')"],
            ["${Classification} === 6", "color('gray')"],
            ["true", "color('white')"]
        ]
    }
});

Фильтрация точек

Отображение только определённых объектов:

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${Classification} === 6"
});

Будут отображаться только здания.


Фильтрация по высоте:

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${POSITION}[2] > 50"
});

Комбинированная фильтрация:

tileset.style = new Cesium.Cesium3DTileStyle({
    show:
        "${Classification} === 6 && " +
        "${POSITION}[2] > 100"
});

Управление уровнем детализации

Cesium автоматически выбирает подходящий уровень детализации.

Основной параметр:

tileset.maximumScreenSpaceError = 8;

Меньшее значение:

tileset.maximumScreenSpaceError = 2;

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

  • более высокая детализация;
  • больше точек на экране.

Недостатки:

  • увеличенное потребление памяти;
  • большая нагрузка на GPU.

Для повышения производительности:

tileset.maximumScreenSpaceError = 32;

В этом случае движок будет отображать меньше данных.


Работа с памятью

Крупные облака точек способны занимать несколько гигабайт данных.

Контроль кэша:

tileset.cacheBytes = 1024 * 1024 * 512;

Пример ограничивает кэш до 512 МБ.


Настройка максимального объёма:

tileset.maximumCacheOverflowBytes =
    1024 * 1024 * 256;

Определение выбранной точки

Выбор объекта выполняется через механизм picking.

const handler =
    new Cesium.ScreenSpaceEventHandler(
        viewer.canvas
    );

handler.setInputAction(function(click) {

    const picked =
        viewer.scene.pick(click.position);

    console.log(picked);

}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

Получение атрибутов точки

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

const feature =
    viewer.scene.pick(click.position);

if (feature) {

    console.log(
        feature.getProperty("Intensity")
    );

    console.log(
        feature.getProperty("Classification")
    );
}

Интеграция с аналитикой

Point Cloud часто используется совместно с:

  • цифровыми двойниками;
  • BIM-моделями;
  • геоинформационными системами;
  • спутниковыми снимками;
  • фотограмметрическими моделями;
  • векторными слоями.

Пример совместного отображения:

viewer.scene.primitives.add(pointCloud);

viewer.scene.primitives.add(buildingTileset);

viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(
        37.62,
        55.75
    ),
    point: {
        pixelSize: 12
    }
});

Сравнение Point Cloud и Photogrammetry

Характеристика Point Cloud Photogrammetry
Точность измерений Очень высокая Средняя
Размер данных Большой Большой
Геометрия Точки Треугольники
Скорость рендера Высокая Средняя
Работа с измерениями Отлично Хорошо
Визуальная реалистичность Средняя Очень высокая

Point Cloud чаще применяется для инженерных задач, тогда как фотограмметрические модели ориентированы на визуализацию.


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

Для крупных проектов рекомендуется:

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

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


Включать Point Cloud Shading

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        attenuation: true
    });

Это уменьшает визуальные артефакты при большом удалении камеры.


Ограничивать Screen Space Error

tileset.maximumScreenSpaceError = 16;

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


Исключать лишние точки

tileset.style = new Cesium.Cesium3DTileStyle({
    show: "${Classification} !== 1"
});

Удаление ненужных категорий снижает нагрузку на графическую подсистему.


Практический пример загрузки LiDAR-облака точек

const viewer = new Cesium.Viewer(
    "cesiumContainer"
);

const tileset =
    await Cesium.Cesium3DTileset.fromUrl(
        "./lidar/tileset.json"
    );

tileset.maximumScreenSpaceError = 8;

tileset.pointCloudShading =
    new Cesium.PointCloudShading({
        attenuation: true,
        eyeDomeLighting: true,
        eyeDomeLightingStrength: 1.2
    });

tileset.style =
    new Cesium.Cesium3DTileStyle({
        color: {
            conditions: [
                [
                    "${Classification} === 2",
                    "color('saddlebrown')"
                ],
                [
                    "${Classification} === 3",
                    "color('green')"
                ],
                [
                    "${Classification} === 6",
                    "color('gray')"
                ],
                [
                    "true",
                    "color('white')"
                ]
            ]
        }
    });

viewer.scene.primitives.add(
    tileset
);

viewer.zoomTo(
    tileset
);

Данный пример демонстрирует типичный сценарий визуализации LiDAR-данных: загрузку облака точек в формате 3D Tiles, настройку уровня детализации, включение улучшенного шейдинга и раскрашивание объектов на основе классификации данных.