В 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.