Работа с размещением 3D-моделей в CesiumJS строится вокруг двух основных подходов: сущности (Entities API) и низкоуровневых примитивов (Primitives API). Выбор подхода определяет контроль над трансформациями, производительность и степень интеграции с геопространственной моделью сцены.
Любая модель в CesiumJS существует не в абстрактном 3D-пространстве, а в глобальной системе координат WGS84, где положение задаётся через долготу, широту и высоту.
Ключевой момент: размещение модели всегда начинается с преобразования геодезических координат в декартову систему.
const position = Cesium.Cartesian3.fromDegrees(
30.5234, // долгота
50.4501, // широта
100 // высота над эллипсоидом
);
Этот шаг является фундаментом всей последующей работы, поскольку CesiumJS оперирует внутренне именно декартовыми координатами.
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
}
});
Модели могут быть привязаны к изменяющимся координатам:
entity.position = new Cesium.CallbackProperty(() => {
return Cesium.Cartesian3.fromDegrees(
30.5234 + Math.sin(Date.now() * 0.0001),
50.4501,
0
);
}, false);
Primitives API применяется, когда требуется полный контроль над матрицами трансформации и производительностью.
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
})
);
Ориентация задаётся через комбинацию:
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
);
Этот механизм критичен при размещении:
Масштабирование может применяться на двух уровнях:
model: {
uri: "models/tree.glb",
scale: 2.5
}
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
);
});
При работе с крупными сценами модели часто размещаются внутри тайловых наборов.
const tileset = new Cesium.Cesium3DTileset({
url: "tileset.json"
});
viewer.scene.primitives.add(tileset);
Модели внутри таких наборов наследуют трансформации тайлов, что позволяет эффективно размещать тысячи объектов без ручного позиционирования.
При массовом размещении объектов критичны следующие аспекты:
Геометрические повторения лучше реализовывать через инстансинг, а не отдельные модели.
Entities удобны, но при тысячах объектов становятся узким местом.
Формат 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
);
});
Такой подход используется для:
На практике наиболее частые проблемы:
Каждая из этих ошибок проявляется как «зависание» модели в воздухе или её частичное погружение в поверхность.
CesiumJS использует glTF как основной формат 3D-моделей.
Критически важные моменты:
model.minimumPixelSize = 128;
model.maximumScale = 200;
model.show = true;
Эти параметры управляют тем, как модель ведёт себя при удалении от камеры, что напрямую влияет на производительность и читаемость сцены.
В основе всех трансформаций лежит WebGL, где каждая модель преобразуется в набор треугольников, отправляемых в GPU.
CesiumJS строит поверх WebGL собственную систему:
Размещение модели фактически определяет матрицу model-view-projection, которая передаётся в шейдеры GPU.