Batching и производительность

В CesiumJS производительность напрямую зависит от того, как сцена преобразуется в минимальное количество GPU-вызовов. Каждый draw call дорог: он включает переключение состояния рендера, привязку буферов, текстур и выполнение вершинных/фрагментных шейдеров. Поэтому основная стратегия оптимизации заключается в агрегации геометрии, материалов и сущностей в крупные пакеты — batching.

CesiumJS использует несколько уровней батчинга: от объединения примитивов в Primitive, до специализированных форматов вроде 3D Tiles с batch tables и инстансингом на уровне GPU.


Базовые принципы батчинга в WebGL контексте

В WebGL каждая отдельная геометрическая сущность может потенциально стать отдельным draw call. При большом количестве объектов сцена быстро упирается в CPU overhead.

Ключевые цели batching:

  • минимизация числа draw calls
  • уменьшение переключений shader program
  • снижение количества bind операций (VAO, VBO, textures)
  • увеличение плотности данных в GPU буферах

CesiumJS решает эти задачи через:

  • объединение геометрии в единые буферы
  • instancing (инстансинг)
  • кластеризацию сущностей
  • tile-based streaming (3D Tiles)
  • batched metadata (BatchTable)

Primitive API и ручной контроль батчинга

На базовом уровне CesiumJS предоставляет Primitive — низкоуровневую сущность, которая позволяет вручную управлять геометрией.

const instance = new Cesium.GeometryInstance({
    geometry: Cesium.BoxGeometry.fromDimensions({
        dimensions: new Cesium.Cartesian3(100000.0, 100000.0, 100000.0)
    }),
    modelMatrix: Cesium.Matrix4.multiplyByTranslation(
        Cesium.Transforms.eastNorthUpToFixedFrame(position),
        new Cesium.Cartesian3(0.0, 0.0, 0.0),
        new Cesium.Matrix4()
    )
});

const primitive = new Cesium.Primitive({
    geometryInstances: [instance],
    appearance: new Cesium.PerInstanceColorAppearance()
});

В данном случае несколько инстансов могут быть объединены в один draw call, если:

  • используется одинаковый Appearance
  • геометрия совместима
  • включён per-instance data layout

Instancing как основной механизм ускорения

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

В CesiumJS инстансинг реализован через GeometryInstance:

  • общий vertex buffer
  • отдельные instance attributes (матрица, цвет, ID)
  • единый shader execution

Типичные сценарии использования:

  • деревья и растительность
  • уличные фонари
  • здания с одинаковой моделью
  • точки интереса (billboards + labels)

Ключевая оптимизация заключается в переносе вариативности из геометрии в instance attributes.


3D Tiles как система массового batching

3D Tiles является центральным механизмом потоковой загрузки и батчинга в CesiumJS. Он объединяет:

  • пространственную иерархию (quadtree / octree)
  • уровни детализации (LOD)
  • батчинг геометрии внутри тайлов
  • metadata через Batch Table

Форматы внутри 3D Tiles:

  • B3DM (batched 3D model)
  • I3DM (instanced 3D model)
  • PNTS (point clouds)
  • CMPT (composite tiles)

Batched 3D Model (B3DM)

B3DM объединяет множество объектов в один mesh с таблицей метаданных.

Структура:

  • binary glTF (геометрия)
  • batch table JSON
  • feature table

Принцип:

  • геометрия всех объектов объединяется
  • каждый объект получает batchId
  • BatchTable хранит свойства (цвет, ID, категории)

Это позволяет:

  • отрисовывать тысячи объектов одним draw call
  • сохранять интерактивность через picking
  • изменять стиль без переразбиения геометрии

Instanced 3D Model (I3DM)

I3DM отличается тем, что геометрия не дублируется.

  • один mesh
  • множество instance transforms
  • минимальное потребление памяти

Используется для:

  • повторяющихся 3D моделей
  • городских объектов
  • инфраструктуры

BatchTable и связь геометрии с данными

Batch Table — это слой, который отделяет визуальную геометрию от семантики.

Он хранит:

  • идентификаторы объектов
  • пользовательские свойства
  • данные для стилизации

Пример структуры:

{
  "name": ["building A", "building B"],
  "height": [50, 120],
  "type": ["residential", "commercial"]
}

Каждый batchId соответствует индексу в массиве.


Frustum Culling и hierarchical batching

CesiumJS активно использует иерархический отсев объектов.

В 3D Tiles применяется:

  • spatial subdivision
  • bounding volume hierarchy
  • screen-space error (SSE)

Каждый tile может быть:

  • загружен
  • выгружен
  • заменён более детализированным

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


Merge vs Instancing vs Tiling

Merge geometry

Плюсы:

  • минимальный draw call
  • простая структура

Минусы:

  • плохая гибкость
  • невозможность динамического изменения частей

Используется для статичных сцен.


Instancing

Плюсы:

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

Минусы:

  • ограниченная вариативность геометрии

Tiling (3D Tiles)

Плюсы:

  • потоковая загрузка
  • масштабируемость до миллионов объектов
  • LOD контроль

Минусы:

  • сложность подготовки данных

Entity API и скрытый batching

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

Однако CesiumJS применяет внутренние оптимизации:

  • billboard clustering
  • label batching
  • dynamic geometry grouping
  • primitive consolidation

Например, BillboardCollection объединяет сотни спрайтов в один draw call.


Billboard и Label batching

Отдельный важный слой оптимизации касается 2D overlay объектов.

BillboardCollection

  • один texture atlas
  • единый vertex buffer
  • instance-based rendering

LabelCollection

  • glyph atlas (шрифтовая текстура)
  • батчинг текста по стилю
  • повторное использование шрифтовых страниц

GPU instancing и attribute packing

CesiumJS активно использует packing данных:

  • матрицы трансформации разбиваются на vec4 атрибуты
  • цвета хранятся в normalized uint8
  • ID кодируются в float textures при необходимости

Это снижает bandwidth между CPU и GPU.


Texture atlasing как часть batching стратегии

Множественные материалы объединяются в:

  • atlas текстуры
  • array textures
  • texture coordinates remapping

Это уменьшает:

  • bindTexture calls
  • shader switches

Особенно важно для:

  • тайлов с повторяющимися материалами
  • городской геометрии
  • terrain текстурирования

Terrain batching

Terrain в CesiumJS строится на:

  • quantized mesh terrain
  • heightmap tiles
  • skirt geometry для швов

Каждый тайл terrain — это:

  • отдельный mesh
  • часть иерархии LOD
  • кандидат на объединение в GPU pipeline

Оптимизация достигается за счёт:

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

Динамическая сцена и проблемы batching

Динамические объекты разрушают batching:

  • изменение позиции ломает instancing cache
  • изменение материала требует split draw calls
  • анимации увеличивают state changes

CesiumJS решает это через:

  • update throttling
  • dirty flags
  • separation static/dynamic primitives

CPU bottlenecks и перераспределение нагрузки

Основные CPU узкие места:

  • подготовка geometry buffers
  • пересборка tiles
  • entity synchronization
  • culling computations

Оптимизации:

  • worker threads для 3D Tiles
  • asynchronous loading pipeline
  • precomputed bounding volumes

WebGL state management и batching

Каждый draw call требует состояния:

  • shader program
  • uniforms
  • buffers
  • textures

CesiumJS минимизирует state changes через:

  • sorting primitives by appearance
  • grouping by material
  • render queue organization

Роль frame graph в эффективности batching

Рендер-пайплайн CesiumJS организован как последовательность проходов:

  • shadow pass
  • opaque pass
  • translucent pass
  • post-processing

В каждом проходе batching пересчитывается отдельно, что снижает конфликт состояний и повышает coherence GPU нагрузки.


Итоговая модель производительности CesiumJS

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

  • пространственного батчинга (3D Tiles)
  • геометрического батчинга (Primitive / merge)
  • инстансинга (GPU instancing)
  • семантического батчинга (BatchTable)
  • текстурного батчинга (atlasing)

Эти уровни работают совместно, создавая многослойную систему, где каждая сущность проходит путь от индивидуального объекта до агрегированного GPU-объекта с минимальным количеством draw calls.