3D модели

MapLibre GL JS поддерживает отображение трёхмерных объектов непосредственно на карте. Использование 3D-моделей позволяет создавать реалистичные визуализации зданий, техники, инфраструктуры, транспортных средств, элементов городской среды и любых других объектов, представленных в формате glTF или GLB.

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

Основой поддержки 3D-моделей является специальный тип слоя — model.


Архитектура отображения 3D-моделей

В процессе визуализации участвуют несколько компонентов:

  1. Источник данных (GeoJSON Source).
  2. Слой типа model.
  3. Файл модели в формате glTF или GLB.
  4. Система координат карты.
  5. Камера MapLibre.

Схема работы выглядит следующим образом:

GeoJSON → Source → Model Layer → GLTF/GLB → WebGL → Карта

Каждая модель привязывается к географическим координатам и автоматически преобразуется из координат карты в мировые координаты WebGL.


Форматы моделей

MapLibre использует формат glTF.

Наиболее распространены два варианта:

glTF

Формат состоит из нескольких файлов:

model.gltf
model.bin
texture.png

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

  • удобство редактирования;
  • отдельное хранение текстур;
  • читаемая JSON-структура.

Недостатки:

  • несколько файлов необходимо загружать одновременно.

GLB

Двоичная версия 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
                    ]
                }
            }
        ]
    }
});

Каждая точка становится местом размещения модели.


Создание слоя model

После добавления источника создаётся слой:

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]

Результат:

  • ширина увеличена в 2 раза;
  • глубина без изменений;
  • высота увеличена в 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 метров.


Использование атрибутов GeoJSON

Свойства объекта могут определять параметры отображения модели.

Источник:

{
    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);
});

Частые причины:

  • неверный путь к файлу;
  • отсутствие текстур;
  • ошибка CORS;
  • повреждённый GLB;
  • неподдерживаемая версия glTF.

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

Слои моделей могут участвовать в обработке событий.

Пример:

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);

В результате карта отображает перемещающиеся грузовые автомобили в реальном времени.


Практический сценарий: цифровой двойник города

В городской модели обычно используются:

  • здания в формате GLB;
  • деревья;
  • фонари;
  • дорожные объекты;
  • транспорт.

Типичная структура проекта:

assets/
 ├─ buildings.glb
 ├─ trees.glb
 ├─ lamps.glb
 └─ vehicles.glb

data/
 ├─ buildings.geojson
 ├─ trees.geojson
 ├─ lamps.geojson
 └─ vehicles.geojson

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


Ограничения технологии

При работе с 3D-моделями необходимо учитывать ряд особенностей:

  • поддержка зависит от возможностей WebGL устройства;
  • большое количество высокополигональных моделей может привести к падению FPS;
  • текстуры высокого разрешения существенно увеличивают объём памяти;
  • сложные анимации лучше выполнять средствами специализированных 3D-движков;
  • точность отображения может снижаться при экстремально больших масштабах карты;
  • качество визуализации зависит от корректности экспорта моделей из Blender, Maya, 3ds Max и других редакторов.

Грамотное использование слоя model, оптимизированных файлов GLB, продуманной системы освещения и корректной организации геоданных позволяет создавать полноценные трёхмерные картографические приложения, объединяющие возможности GIS и современных WebGL-технологий.