Размещение моделей на сцене

Работа с размещением 3D-моделей в CesiumJS строится вокруг двух основных подходов: сущности (Entities API) и низкоуровневых примитивов (Primitives API). Выбор подхода определяет контроль над трансформациями, производительность и степень интеграции с геопространственной моделью сцены.


Любая модель в CesiumJS существует не в абстрактном 3D-пространстве, а в глобальной системе координат WGS84, где положение задаётся через долготу, широту и высоту.

Ключевой момент: размещение модели всегда начинается с преобразования геодезических координат в декартову систему.

const position = Cesium.Cartesian3.fromDegrees(
    30.5234,   // долгота
    50.4501,   // широта
    100        // высота над эллипсоидом
);

Этот шаг является фундаментом всей последующей работы, поскольку CesiumJS оперирует внутренне именно декартовыми координатами.


Размещение модели через Entities API

Entities API обеспечивает высокоуровневую абстракцию, скрывая математику преобразований и матриц.

Создание модели в составе сущности

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

const entity = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(30.5234, 50.4501, 0),
    model: {
        uri: "models/building.glb",
        scale: 1.0,
        minimumPixelSize: 64
    }
});

Особенности подхода

  • автоматическое управление матрицами трансформации
  • интеграция с системой выбора объектов (picking)
  • поддержка динамических свойств (Property system)
  • упрощённая работа с анимацией и обновлениями

Динамическое позиционирование

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

entity.position = new Cesium.CallbackProperty(() => {
    return Cesium.Cartesian3.fromDegrees(
        30.5234 + Math.sin(Date.now() * 0.0001),
        50.4501,
        0
    );
}, false);

Низкоуровневое размещение через Primitives API

Primitives API применяется, когда требуется полный контроль над матрицами трансформации и производительностью.

Создание модели через Cesium.Model

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

const position = Cesium.Cartesian3.fromDegrees(30.5234, 50.4501, 0);

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

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

const model = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
        url: "models/vehicle.glb",
        modelMatrix: modelMatrix,
        scale: 1.0
    })
);

Ключевые особенности

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

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

Ориентация задаётся через комбинацию:

  • heading (курс)
  • pitch (наклон)
  • roll (крен)
const heading = Cesium.Math.toRadians(45);
const pitch = Cesium.Math.toRadians(10);
const roll = Cesium.Math.toRadians(0);

const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

Преобразование в матрицу сцены:

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

Этот механизм критичен при размещении:

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

Работа с масштабированием моделей

Масштабирование может применяться на двух уровнях:

Через Entities API

model: {
    uri: "models/tree.glb",
    scale: 2.5
}

Через Primitives API

Cesium.Model.fromGltf({
    url: "models/tree.glb",
    modelMatrix: modelMatrix,
    scale: 2.5
});

Важно учитывать: масштабирование влияет не только на визуальный размер, но и на bounding volume, что может затрагивать отбраковку (culling).


Привязка моделей к поверхности Земли

Для размещения объектов на рельефе используется sampling высоты.

const cartographic = Cesium.Cartographic.fromDegrees(30.5234, 50.4501);

const position = Cesium.Cartesian3.fromRadians(
    cartographic.longitude,
    cartographic.latitude,
    cartographic.height
);

Для точной посадки на terrain применяется:

Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [
    cartographic
]).then((updatedPositions) => {
    const position = Cesium.Cartesian3.fromRadians(
        updatedPositions[0].longitude,
        updatedPositions[0].latitude,
        updatedPositions[0].height
    );
});

Использование 3D Tiles и интеграция моделей

При работе с крупными сценами модели часто размещаются внутри тайловых наборов.

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

viewer.scene.primitives.add(tileset);

Модели внутри таких наборов наследуют трансформации тайлов, что позволяет эффективно размещать тысячи объектов без ручного позиционирования.


Производительность при большом количестве моделей

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

1. Использование Instancing

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

2. Минимизация Entities

Entities удобны, но при тысячах объектов становятся узким местом.

3. Использование простых glTF моделей

Формат glTF предпочтителен из-за:

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

Камера и визуальный контроль размещённых моделей

Размещение модели тесно связано с положением камеры.

viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(30.5234, 50.4501, 1000)
});

Корректная настройка камеры позволяет:

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

Привязка моделей к движущимся координатам

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

viewer.scene.preRender.addEventListener(() => {
    const time = Date.now() * 0.001;

    const position = Cesium.Cartesian3.fromDegrees(
        30.5234 + Math.sin(time) * 0.01,
        50.4501 + Math.cos(time) * 0.01,
        100
    );

    const hpr = new Cesium.HeadingPitchRoll(time, 0, 0);

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

Такой подход используется для:

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

Ошибки позиционирования и их причины

На практике наиболее частые проблемы:

  • несоответствие высотной модели terrain
  • неверная система координат исходных данных
  • отсутствие преобразования degrees → radians
  • неправильная ориентация heading/pitch/roll
  • конфликт между Entity и Primitive трансформациями

Каждая из этих ошибок проявляется как «зависание» модели в воздухе или её частичное погружение в поверхность.


Особенности работы с glTF моделями

CesiumJS использует glTF как основной формат 3D-моделей.

Критически важные моменты:

  • единицы измерения считаются в метрах
  • pivot модели влияет на поведение при вращении
  • материалы PBR корректно отображаются только при физически корректном освещении сцены

Управление видимостью и уровнем детализации

model.minimumPixelSize = 128;
model.maximumScale = 200;
model.show = true;

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


Связь размещения моделей с WebGL пайплайном

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

CesiumJS строит поверх WebGL собственную систему:

  • батчинга объектов
  • управления буферами вершин
  • оптимизации отрисовки по кадрам
  • frustum culling на уровне сцены

Размещение модели фактически определяет матрицу model-view-projection, которая передаётся в шейдеры GPU.