MapLibre GL JS поддерживает отображение трёхмерных объектов непосредственно на карте. Использование 3D-моделей позволяет создавать реалистичные визуализации зданий, техники, инфраструктуры, транспортных средств, элементов городской среды и любых других объектов, представленных в формате glTF или GLB.
Трёхмерные объекты отображаются как часть сцены WebGL и могут взаимодействовать с картой на уровне камеры, масштабирования, вращения и наклона. Благодаря этому становится возможным создание навигационных систем, цифровых двойников городов, геоинформационных систем, симуляторов и интерактивных картографических приложений.
Основой поддержки 3D-моделей является специальный тип слоя —
model.
В процессе визуализации участвуют несколько компонентов:
GeoJSON Source).model.Схема работы выглядит следующим образом:
GeoJSON → Source → Model Layer → GLTF/GLB → WebGL → Карта
Каждая модель привязывается к географическим координатам и автоматически преобразуется из координат карты в мировые координаты WebGL.
MapLibre использует формат glTF.
Наиболее распространены два варианта:
Формат состоит из нескольких файлов:
model.gltf
model.bin
texture.png
Преимущества:
Недостатки:
Двоичная версия glTF.
building.glb
Преимущества:
Недостатки:
Для веб-карт чаще используется именно GLB.
Для полноценного отображения 3D требуется наклон карты.
Создание карты:
const map = new maplibregl.Map({
container: "map",
style: "style.json",
center: [37.6176, 55.7558],
zoom: 17,
pitch: 60,
bearing: 30
});
Параметры:
| Свойство | Назначение |
|---|---|
zoom |
масштаб |
pitch |
наклон камеры |
bearing |
вращение карты |
Без наклона трёхмерные объекты могут выглядеть как обычные плоские элементы.
Модели размещаются через GeoJSON.
Простейший источник:
map.addSource("objects", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
37.6176,
55.7558
]
}
}
]
}
});
Каждая точка становится местом размещения модели.
После добавления источника создаётся слой:
map.addLayer({
id: "cars",
type: "model",
source: "objects",
layout: {
"model-id": "car"
}
});
Здесь:
type: "model" сообщает движку о необходимости
отображения трёхмерных объектов;model-id связывает слой с конкретной моделью.Перед использованием модель необходимо зарегистрировать.
Пример:
map.addModel("car", {
uri: "/models/car.glb"
});
После регистрации появляется идентификатор:
car
Именно его использует свойство:
"model-id": "car"
map.on("load", () => {
map.addModel("car", {
uri: "/models/car.glb"
});
map.addSource("cars", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
37.6176,
55.7558
]
}
}
]
}
});
map.addLayer({
id: "cars-layer",
type: "model",
source: "cars",
layout: {
"model-id": "car"
}
});
});
Результатом станет отображение автомобиля в заданной точке карты.
Размер модели редко соответствует размерам карты.
Для изменения размеров используется масштаб.
Пример:
map.addModel("tree", {
uri: "/models/tree.glb",
scale: [2, 2, 2]
});
Массив содержит коэффициенты:
[x, y, z]
Например:
scale: [10, 10, 10]
увеличивает объект в десять раз.
Разные оси могут иметь разные значения.
Пример:
scale: [2, 1, 5]
Результат:
Подобный подход используется при визуализации инженерных объектов и специализированных конструкций.
Многие модели экспортируются с неправильной ориентацией относительно карты.
Используется параметр вращения:
rotation: [0, 90, 0]
Порядок:
[x, y, z]
Пример:
map.addModel("airplane", {
uri: "/models/airplane.glb",
rotation: [0, 180, 0]
});
Самолёт будет развернут на 180 градусов.
По умолчанию объект располагается на уровне поверхности карты.
Для поднятия модели используется смещение:
translation: [0, 0, 30]
Здесь:
30 метров вверх
Пример:
map.addModel("drone", {
uri: "/models/drone.glb",
translation: [0, 0, 100]
});
Дрон будет находиться на высоте 100 метров.
Свойства объекта могут определять параметры отображения модели.
Источник:
{
type: "Feature",
properties: {
type: "truck"
},
geometry: {
type: "Point",
coordinates: [37.61, 55.75]
}
}
Затем свойства используются в выражениях стиля.
Это позволяет отображать разные модели на основе данных из GeoJSON.
Коллекция объектов:
{
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [37.61, 55.75]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [37.62, 55.76]
}
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [37.63, 55.77]
}
}
]
}
MapLibre автоматически создаёт экземпляр модели для каждой точки.
Особенно эффектно модели выглядят совместно с трёхмерным рельефом.
Подключение DEM:
map.setTerrain({
source: "terrain",
exaggeration: 1.5
});
После включения рельефа модели автоматически размещаются относительно высот местности.
Это позволяет строить:
Трёхмерные модели реагируют на освещение.
Настройка источника света:
map.setLight({
anchor: "viewport",
color: "#ffffff",
intensity: 0.8
});
Основные параметры:
| Параметр | Описание |
|---|---|
color |
цвет света |
intensity |
интенсивность |
anchor |
система координат источника |
Корректная настройка света существенно повышает реалистичность сцены.
Положение объекта можно изменять динамически.
Пример:
function moveCar(lng, lat) {
source.setData({
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat]
}
}
]
});
}
При каждом обновлении координат модель перемещается по карте.
Подобный подход применяется для:
Для имитации движения можно изменять угол поворота.
Пример:
let angle = 0;
function update() {
angle += 1;
map.setModelOptions("car", {
rotation: [0, angle, 0]
});
requestAnimationFrame(update);
}
update();
В результате создаётся непрерывное вращение объекта.
При работе с сотнями и тысячами объектов необходимо учитывать производительность.
Основные рекомендации:
Лучше:
1 модель × 1000 экземпляров
чем:
1000 различных моделей
Для веб-карт желательно использовать:
до 5 000 полигонов
на один объект.
Высокополигональные модели быстро перегружают GPU.
Рекомендуются форматы:
WebP
KTX2
Basis Universal
Это снижает объём передаваемых данных.
LOD позволяет отображать разные версии объекта.
Например:
Далеко → 500 полигонов
Средне → 2000 полигонов
Близко → 10000 полигонов
Подход значительно повышает производительность крупных сцен.
Нередко модель не отображается из-за проблем с путём или ресурсами.
Контроль ошибок:
map.on("error", (event) => {
console.error(event.error);
});
Частые причины:
Слои моделей могут участвовать в обработке событий.
Пример:
map.on("click", "cars-layer", (event) => {
console.log(
event.features[0]
);
});
После щелчка можно:
Регистрация модели:
map.addModel("truck", {
uri: "/models/truck.glb"
});
Источник данных:
map.addSource("fleet", {
type: "geojson",
data: fleetData
});
Слой:
map.addLayer({
id: "fleet-layer",
type: "model",
source: "fleet",
layout: {
"model-id": "truck"
}
});
Периодическое обновление координат:
setInterval(async () => {
const response =
await fetch("/api/fleet");
const data =
await response.json();
fleetSource.setData(data);
}, 3000);
В результате карта отображает перемещающиеся грузовые автомобили в реальном времени.
В городской модели обычно используются:
Типичная структура проекта:
assets/
├─ buildings.glb
├─ trees.glb
├─ lamps.glb
└─ vehicles.glb
data/
├─ buildings.geojson
├─ trees.geojson
├─ lamps.geojson
└─ vehicles.geojson
Каждый тип объектов получает собственный слой model,
благодаря чему обеспечивается независимое управление отображением,
фильтрацией и обновлением данных.
При работе с 3D-моделями необходимо учитывать ряд особенностей:
Грамотное использование слоя model, оптимизированных
файлов GLB, продуманной системы освещения и корректной организации
геоданных позволяет создавать полноценные трёхмерные картографические
приложения, объединяющие возможности GIS и современных
WebGL-технологий.