Загрузка glTF моделей

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

CesiumJS поддерживает загрузку glTF через несколько уровней API: низкоуровневый Model, высокоуровневые сущности Entity и интеграцию через 3D Tiles. Выбор подхода определяется задачами: единичная модель, динамическая сцена или крупномасштабный потоковый датасет.


Архитектура загрузки glTF в сцену

Внутри CesiumJS модель glTF проходит несколько этапов:

  • загрузка ресурса (локальный файл, URL или Cesium Ion)
  • разбор структуры glTF (узлы, меши, материалы)
  • создание GPU-буферов
  • привязка к матрице трансформации сцены
  • интеграция в render loop

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


Базовая загрузка через Model API

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

import * as Cesium from "cesium";

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

const model = Cesium.Model.fromGltf({
  url: "models/vehicle.glb",
  modelMatrix: Cesium.Matrix4.fromTranslation(
    Cesium.Cartesian3.fromDegrees(30.5, 50.4, 100)
  ),
  scale: 1.0
});

viewer.scene.primitives.add(model);

Ключевые параметры

  • url — путь к .gltf или .glb
  • modelMatrix — позиция, ориентация и масштаб в мировых координатах
  • scale — дополнительный коэффициент масштабирования
  • minimumPixelSize — минимальный размер модели на экране

Асинхронная загрузка и управление ресурсами

Современный подход использует fromGltfAsync, позволяющий не блокировать основной поток.

const model = await Cesium.Model.fromGltfAsync({
  url: "models/building.glb",
  modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
    Cesium.Cartesian3.fromDegrees(37.6173, 55.7558, 0)
  )
});

viewer.scene.primitives.add(model);

Асинхронная загрузка особенно важна при работе с тяжелыми сценами, где требуется плавная отрисовка без фризов интерфейса.


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

Entity-подход интегрирует glTF модель в декларативную модель сцены.

const entity = viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(10.0, 45.0, 0),
  model: {
    uri: "models/airplane.glb",
    scale: 2.0,
    minimumPixelSize: 64
  }
});

Этот способ используется в сценариях, где требуется:

  • динамическое обновление объектов
  • привязка к данным (датчики, трекинг)
  • временные анимации
  • взаимодействие с Entity API (selection, events)

Геопривязка моделей

Ключевая особенность CesiumJS — строгая работа с геодезическими координатами.

Преобразование координат

const position = Cesium.Cartesian3.fromDegrees(
  69.2401,
  41.2995,
  500
);

Фрейм восток-север-вверх

const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);

Этот метод обеспечивает корректную ориентацию модели относительно поверхности Земли.


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

Для точного позиционирования используется комбинация Heading-Pitch-Roll:

const hpr = new Cesium.HeadingPitchRoll(
  Cesium.Math.toRadians(90),
  Cesium.Math.toRadians(0),
  Cesium.Math.toRadians(0)
);

const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
  position,
  hpr
);

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

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

Работа с масштабированием и LOD-поведением

glTF модели часто требуют адаптации к масштабу сцены.

model.scale = 5.0;
model.minimumPixelSize = 128;
model.maximumScale = 20000;

minimumPixelSize

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

maximumScale

Ограничивает чрезмерное увеличение модели при приближении.


Материалы и освещение

CesiumJS поддерживает PBR-материалы glTF (Physically Based Rendering):

  • metallic-roughness workflow
  • normal maps
  • emissive maps
  • occlusion maps

Влияние освещения сцены

viewer.scene.globe.enableLighting = true;

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

  • положение солнца
  • время суток
  • географическую широту

Draco и KTX2 оптимизация

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

Draco compression

Сжимает геометрию:

Cesium.Model.fromGltf({
  url: "compressed.glb"
});

Cesium автоматически распознаёт Draco при наличии декодера.

KTX2 текстуры

Используются для GPU-декодируемых текстур, уменьшая нагрузку на память.


Кэширование и потоковая загрузка

CesiumJS использует внутренний кэш ресурсов:

  • повторное использование буферов
  • дедупликация текстур
  • ленивую загрузку узлов

При работе с удалёнными серверами важны:

  • CORS-заголовки
  • корректные MIME-типы
  • поддержка HTTP range requests

Интеграция с 3D Tiles

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

const tileset = new Cesium.Cesium3DTileset({
  url: "tileset.json"
});

viewer.scene.primitives.add(tileset);

Внутри каждого тайла может находиться glTF-геометрия, что обеспечивает:

  • потоковую подгрузку
  • LOD-структуру
  • масштабирование до городов и стран

Анимации glTF

CesiumJS поддерживает встроенные анимации:

model.activeAnimations.addAll();

Управление:

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

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

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

Избыточная геометрия

Решается:

  • упрощением mesh
  • использованием LOD
  • Draco compression

Тяжёлые текстуры

Решается:

  • KTX2
  • mipmapping
  • уменьшение разрешения

Частые пересоздания моделей

Решается:

  • переиспользованием Model instances
  • кэшированием ресурсов

Пример комплексной загрузки с настройками

const position = Cesium.Cartesian3.fromDegrees(55.751244, 37.618423, 50);

const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
  position,
  new Cesium.HeadingPitchRoll(
    Cesium.Math.toRadians(45),
    0,
    0
  )
);

const model = Cesium.Model.fromGltf({
  url: "models/drone.glb",
  modelMatrix: modelMatrix,
  scale: 3.0,
  minimumPixelSize: 128,
  shadows: Cesium.ShadowMode.ENABLED
});

viewer.scene.primitives.add(model);

model.readyPromise.then(() => {
  model.activeAnimations.addAll({
    loop: Cesium.ModelAnimationLoop.REPEAT
  });
});

Взаимодействие с камерой и сценой

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

  • слежение за объектом
  • фиксированная ориентация
  • динамическое обновление позиции
viewer.trackedEntity = entity;

или через программное управление:

viewer.camera.lookAt(position, new Cesium.Cartesian3(0, -1000, 500));

Обновление позиции в реальном времени

Для динамических моделей используется изменение modelMatrix:

model.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
  Cesium.Cartesian3.fromDegrees(newLon, newLat, newHeight)
);

Это позволяет реализовать:

  • трекинг транспорта
  • симуляцию полётов
  • визуализацию IoT-объектов

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

CesiumJS использует Earth-Centered Earth-Fixed (ECEF):

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

Это влияет на:

  • ориентацию моделей
  • вычисление расстояний
  • поведение LOD

Итоговая модель взаимодействия с glTF

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

  1. загрузка glTF
  2. декодирование буферов
  3. создание GPU ресурсов
  4. привязка к сцене
  5. участие в render loop
  6. обновление в каждом кадре при необходимости

Этот процесс делает возможным отображение сложных 3D сцен в реальном времени даже на ограниченном оборудовании.