Пользовательские геометрии

Система визуализации CesiumJS предоставляет набор готовых геометрических примитивов: прямоугольники, полигоны, эллипсы, коридоры, цилиндры, сферы и многие другие. Однако при разработке специализированных геоинформационных систем, инженерных платформ, цифровых двойников или научных приложений часто возникает необходимость отображать объекты, форма которых не соответствует стандартным примитивам.

В таких случаях используются пользовательские геометрии (Custom Geometries) — объекты, создаваемые вручную путем определения вершин, индексов и дополнительных атрибутов.

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

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

Основным классом для создания собственной геометрии является Cesium.Geometry.


Архитектура геометрий в CesiumJS

Геометрический объект состоит из нескольких компонентов:

Компонент Назначение
Geometry Хранение вершин и индексов
GeometryAttribute Атрибуты вершин
GeometryInstance Экземпляр геометрии
Primitive Отображение на сцене
Appearance Настройка визуального представления

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

Geometry
    ↓
GeometryInstance
    ↓
Primitive
    ↓
Scene

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


Структура объекта Geometry

Минимальная пользовательская геометрия содержит:

const geometry = new Cesium.Geometry({
    attributes: {
        position: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.DOUBLE,
            componentsPerAttribute: 3,
            values: positions
        })
    },
    indices: indices,
    primitiveType: Cesium.PrimitiveType.TRIANGLES,
    boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
});

Основные свойства:

attributes

Содержит набор атрибутов вершин.

Пример:

attributes: {
    position: ...,
    normal: ...,
    st: ...,
    color: ...
}

indices

Определяет порядок соединения вершин.

primitiveType

Указывает способ интерпретации вершин.

Поддерживаются:

Cesium.PrimitiveType.POINTS
Cesium.PrimitiveType.LINES
Cesium.PrimitiveType.LINE_LOOP
Cesium.PrimitiveType.LINE_STRIP
Cesium.PrimitiveType.TRIANGLES
Cesium.PrimitiveType.TRIANGLE_STRIP
Cesium.PrimitiveType.TRIANGLE_FAN

boundingSphere

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


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

Любая геометрия начинается с описания вершин.

Например, треугольник:

const positions = new Float64Array([
     0.0, 0.0, 0.0,
   100.0, 0.0, 0.0,
     0.0, 100.0, 0.0
]);

Каждая вершина содержит три координаты:

x
y
z

В Cesium координаты обычно задаются в мировой системе координат ECEF (Earth-Centered Earth-Fixed).

Для перевода географических координат используется:

const cartesian = Cesium.Cartesian3.fromDegrees(
    37.6173,
    55.7558,
    100
);

Создание собственного треугольника

Простейшая пользовательская геометрия:

const positions = new Float64Array([
    0.0, 0.0, 0.0,
    500.0, 0.0, 0.0,
    0.0, 500.0, 0.0
]);

const indices = new Uint16Array([
    0, 1, 2
]);

const geometry = new Cesium.Geometry({
    attributes: {
        position: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.DOUBLE,
            componentsPerAttribute: 3,
            values: positions
        })
    },
    indices: indices,
    primitiveType: Cesium.PrimitiveType.TRIANGLES,
    boundingSphere:
        Cesium.BoundingSphere.fromVertices(positions)
});

После создания геометрию необходимо обернуть в экземпляр:

const instance = new Cesium.GeometryInstance({
    geometry: geometry
});

Добавление Primitive

Для отображения геометрии создается примитив.

viewer.scene.primitives.add(
    new Cesium.Primitive({
        geometryInstances: instance,
        appearance: new Cesium.PerInstanceColorAppearance({
            flat: true
        }),
        asynchronous: false
    })
);

Цвета вершин

Каждая вершина может иметь собственный цвет.

Создание массива цветов:

const colors = new Uint8Array([
    255, 0, 0, 255,
    0, 255, 0, 255,
    0, 0, 255, 255
]);

Добавление атрибута:

color: new Cesium.GeometryAttribute({
    componentDatatype:
        Cesium.ComponentDatatype.UNSIGNED_BYTE,
    componentsPerAttribute: 4,
    normalize: true,
    values: colors
})

Теперь каждая вершина получает свой цвет.


Интерполяция цветов

При использовании разных цветов на вершинах GPU автоматически выполняет интерполяцию.

Например:

Вершина 1 → красный
Вершина 2 → зелёный
Вершина 3 → синий

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

Такой подход активно применяется для:

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

Индексы и формирование полигонов

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

Рассмотрим квадрат:

0 ----- 1
|       |
|       |
3 ----- 2

Вершины:

const positions = new Float64Array([
    0, 0, 0,
    1, 0, 0,
    1, 1, 0,
    0, 1, 0
]);

Индексы:

const indices = new Uint16Array([
    0, 1, 2,
    0, 2, 3
]);

Квадрат состоит из двух треугольников.


Нормали

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

Она необходима для:

  • освещения;
  • теней;
  • шейдеров;
  • корректного отражения света.

Пример массива нормалей:

const normals = new Float32Array([
    0, 0, 1,
    0, 0, 1,
    0, 0, 1,
    0, 0, 1
]);

Добавление:

normal: new Cesium.GeometryAttribute({
    componentDatatype:
        Cesium.ComponentDatatype.FLOAT,
    componentsPerAttribute: 3,
    values: normals
})

Вычисление нормалей

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

Пусть:

A
B
C

Тогда:

AB = B - A
AC = C - A

Нормаль:

N = AB × AC

После вычисления выполняется нормализация вектора.

Это обеспечивает единичную длину нормали.


Текстурные координаты

Для наложения текстур используются координаты UV.

В Cesium они называются st.

Пример:

const sts = new Float32Array([
    0, 0,
    1, 0,
    1, 1,
    0, 1
]);

Добавление:

st: new Cesium.GeometryAttribute({
    componentDatatype:
        Cesium.ComponentDatatype.FLOAT,
    componentsPerAttribute: 2,
    values: sts
})

Работа с текстурами

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

appearance: new Cesium.MaterialAppearance({
    material: Cesium.Material.fromType(
        "Image",
        {
            image: "texture.jpg"
        }
    )
})

Координаты st определяют, какая область изображения будет отображаться на поверхности.


Создание объёмной фигуры

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

Например:

Куб
Пирамида
Призма
Башня
Резервуар
Мост

Для этого необходимо описать:

  • вершины;
  • треугольники каждой грани;
  • нормали граней.

Количество треугольников быстро возрастает, поэтому обычно геометрия генерируется программно.


Генерация куба

Вершины куба:

const positions = [
    -1, -1, -1,
     1, -1, -1,
     1,  1, -1,
    -1,  1, -1,

    -1, -1,  1,
     1, -1,  1,
     1,  1,  1,
    -1,  1,  1
];

Каждая грань состоит из двух треугольников.

Всего:

6 граней
12 треугольников
36 индексов

Геометрия на поверхности Земли

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

Создание вершин:

const p1 = Cesium.Cartesian3.fromDegrees(
    37.61, 55.75, 0
);

const p2 = Cesium.Cartesian3.fromDegrees(
    37.62, 55.75, 0
);

const p3 = Cesium.Cartesian3.fromDegrees(
    37.62, 55.76, 0
);

Преобразование в массив:

const positions =
    new Float64Array([
        p1.x, p1.y, p1.z,
        p2.x, p2.y, p2.z,
        p3.x, p3.y, p3.z
    ]);

Теперь геометрия располагается непосредственно на глобусе.


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

Cesium предоставляет набор инструментов обработки геометрии.

Основной модуль:

Cesium.GeometryPipeline

Он позволяет:

  • генерировать нормали;
  • преобразовывать атрибуты;
  • оптимизировать вершины;
  • выполнять компрессию данных.

Пример:

geometry =
    Cesium.GeometryPipeline.computeNormal(
        geometry
    );

Оптимизация пользовательских геометрий

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

Основные методы оптимизации:

Повторное использование вершин

Плохо:

каждый треугольник имеет собственные вершины

Хорошо:

треугольники используют общие вершины

Минимизация атрибутов

Если текстуры не используются:

st

не следует создавать.

Если освещение отсутствует:

normal

также можно исключить.


Корректный BoundingSphere

Неверно рассчитанная сфера приводит к лишней отрисовке.

Правильный вариант:

Cesium.BoundingSphere.fromVertices(
    positions
);

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

Следует использовать:

Float32Array
Float64Array
Uint16Array
Uint32Array

Вместо:

Array

Это уменьшает потребление памяти и ускоряет передачу данных в GPU.


Геометрии и шейдеры

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

Дополнительные атрибуты могут передаваться напрямую в GPU.

Например:

temperature
pressure
velocity
density

Каждая вершина может содержать научные или инженерные данные.

Шейдер затем использует их для расчета цвета, прозрачности или анимации.


Пользовательские атрибуты

Создание собственного атрибута:

customValue:
    new Cesium.GeometryAttribute({
        componentDatatype:
            Cesium.ComponentDatatype.FLOAT,
        componentsPerAttribute: 1,
        values: values
    })

Такой атрибут становится доступным внутри GLSL-шейдера.

Подобный подход широко применяется при визуализации:

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

Динамическое обновление геометрии

Если форма объекта меняется во времени, возможны два подхода.

Пересоздание геометрии

Создается новый объект:

Geometry
GeometryInstance
Primitive

Старый удаляется.

Подходит для редких обновлений.


Обновление буферов

Для высокочастотной анимации предпочтительно изменять содержимое буферов GPU.

Такой подход применяется при отображении:

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

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

Пользовательские геометрии особенно востребованы в следующих задачах:

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

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