Оптимизация геометрии

Геометрия в CesiumJS формируется на нескольких уровнях абстракции: Entities → Primitives → GeometryInstance → WebGL buffers. Основная стоимость производительности возникает не на этапе рендера, а на этапе подготовки данных: тесселяция, трансформация координат, генерация индексов и загрузка вершин в GPU.

Ключевые узлы нагрузки:

  • генерация вершинной сетки (CPU-bound)
  • передача буферов в WebGL (GPU upload)
  • избыточная детализация геометрии
  • отсутствие батчинга и повторного использования буферов
  • неэффективные bounding volumes, приводящие к лишнему рендеру

Оптимизация геометрии в CesiumJS всегда сводится к уменьшению объёма данных и снижению числа draw calls при сохранении визуальной точности.


Примитивы вместо Entities как базовый уровень оптимизации

Entity API удобен для разработки, но создаёт дополнительные накладные расходы:

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

Primitives работают ближе к WebGL и позволяют:

  • повторно использовать GeometryInstance
  • минимизировать перерасчёт данных
  • объединять объекты в батчи

Типовая замена:

  • Entity Polygon → Primitive + GeometryInstance + PerInstanceColorAppearance
  • Entity Polyline → Primitive + PolylineGeometry

Ключевой принцип: статическая геометрия всегда должна уходить в Primitive слой.


Батчинг геометрии и снижение draw calls

Каждый draw call в WebGL — значительная стоимость. CesiumJS позволяет объединять геометрию через:

  • GeometryInstance
  • единый Primitive
  • общий Appearance

Пример стратегии:

  • множество зданий → один Primitive
  • различие задаётся через per-instance attributes

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

  • один вызов отрисовки вместо сотен
  • единый буфер вершин
  • кэширование GPU ресурсов

Ограничение:

  • одинаковый материал у всех инстансов

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

При повторяющейся геометрии (деревья, столбы, здания) применяется instancing:

  • одна базовая геометрия
  • трансформации через model matrix
  • минимальный объём памяти

Особенно эффективно при:

  • городских сценах
  • инженерных моделях
  • симуляциях инфраструктуры

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


Упрощение полигонов и контроль плотности сетки

Избыточная плотность вершин — один из главных источников деградации FPS.

Методы оптимизации:

  • decimation (сокращение полигонов)
  • edge collapse
  • removal of collinear points
  • adaptive simplification по экранному размеру

Практическое правило:

  • детализация должна зависеть от пиксельного размера объекта на экране

Если объект занимает менее нескольких пикселей — геометрия должна деградировать до минимального представления.


Использование Quantized-geometry и сжатых атрибутов

CesiumJS поддерживает оптимизированные форматы хранения вершин:

  • quantized positions
  • compressed normals
  • oct-encoded vectors

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

  • снижение памяти до 4–8 раз
  • уменьшение bandwidth загрузки
  • ускорение передачи в GPU

Особенно эффективно в:

  • 3D Tiles
  • больших CAD-моделях
  • глобальных сценах

Draco-сжатие и оптимизация glTF

Для моделей glTF применяется Draco compression:

  • сжатие индексов
  • сжатие вершин
  • уменьшение веса модели

Плюсы:

  • резкое снижение размера ассетов
  • ускорение загрузки

Минусы:

  • дополнительная CPU-декомпрессия
  • увеличение времени первого кадра

Оптимальный подход:

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

3D Tiles как основной механизм оптимизации

3D Tiles — ключевая система оптимизации больших геометрических наборов.

Основные механизмы:

  • иерархия уровней детализации (LOD)
  • пространственное деление (quadtree/octree)
  • bounding volumes (sphere, box, region)
  • стриминг по экранному пространству

Оптимизационные эффекты:

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

Критический параметр: screen space error (SSE) Он управляет балансом между качеством и производительностью.


Контроль видимости и отсечение геометрии

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

  • frustum culling
  • backface culling
  • occlusion culling (частично через tilesets)
  • clipping planes

Особенно важно:

  • правильно задавать bounding volumes
  • избегать чрезмерно больших bounding box’ов
  • разделять геометрию по логическим регионам

Ошибки в bounding volume приводят к:

  • отрисовке невидимых объектов
  • перегрузке GPU pipeline

Разделение больших геометрий

Монолитные меши ухудшают производительность:

Проблемы:

  • отсутствие LOD
  • невозможность culling на уровне частей
  • рост времени загрузки

Решение:

  • деление по пространству
  • деление по типам объектов
  • разбиение по уровню детализации

Оптимальная гранулярность:

  • объект должен быть достаточно крупным для батчинга
  • но достаточно маленьким для отсечения

Оптимизация атрибутов вершин

Каждый дополнительный атрибут увеличивает:

  • размер буфера
  • время передачи в GPU
  • нагрузку на шейдер

Рекомендуется минимальный набор:

  • position
  • normal (если требуется освещение)
  • st (если есть текстуры)

Удаляются:

  • неиспользуемые UV-каналы
  • лишние tangent/bitangent
  • дублирующиеся color attributes

Геометрия и terrain: clamping и декуплинг

При работе с рельефом Cesium terrain:

  • geometry clamped to ground создаёт дополнительные вычисления
  • пересчёт высот увеличивает CPU нагрузку

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

  • использование precomputed heights
  • минимизация dynamic clamping
  • переход к baked geometry при статике

Dynamic vs Static геометрия

Ключевое разделение:

Статическая геометрия

  • загружается один раз
  • не изменяется
  • может быть агрессивно оптимизирована

Динамическая геометрия

  • требует пересчёта каждый кадр или при изменении камеры
  • должна быть максимально облегчена

Практический принцип:

  • любая геометрия без анимации или взаимодействия считается статической

Минимизация пересчётов и requestRenderMode

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

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

  • requestRenderMode = true
  • рендер только при изменениях сцены

Эффект:

  • снижение CPU нагрузки
  • уменьшение энергопотребления
  • стабильный FPS в статических сценах

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

GeometryPipeline позволяет:

  • оптимизировать индексы
  • объединять буферы
  • вычислять bounding spheres
  • трансформировать геометрию перед GPU

Ключевые стадии:

  • vertex cache optimization
  • index reordering
  • normal computation
  • bounding computation

Оптимизация полилиний и кривых

Polyline geometry часто становится узким местом:

Проблемы:

  • слишком много сегментов
  • высокая плотность точек

Методы оптимизации:

  • Douglas–Peucker simplification
  • adaptive sampling по экранному расстоянию
  • ограничение максимального числа сегментов

GPU-ориентированная оптимизация геометрии

На уровне GPU важны:

  • снижение bandwidth
  • уменьшение overdraw
  • минимизация state changes

Подходы:

  • объединение материалов
  • использование одинаковых шейдеров
  • сокращение переключений текстур

Баланс точности и производительности

Оптимизация геометрии в CesiumJS всегда является компромиссом:

  • высокая детализация → высокая CPU/GPU нагрузка
  • агрессивная оптимизация → потеря визуальной точности

Практический критерий:

  • геометрия должна соответствовать экранному разрешению, а не реальной плотности данных

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