В трёхмерной визуализации карт в MapLibre GL JS высота зданий формируется не из геометрии растрового изображения, а из атрибутов векторных тайлов. Основной принцип заключается в том, что каждое здание представляет собой полигон с набором свойств, среди которых ключевым является значение высоты.
Чаще всего используются данные OpenStreetMap, где высота может храниться в различных тегах:
height — фактическая высота здания в метрахbuilding:levels — количество этажейmin_height — высота основания (для зданий на опорах или
стилобатах)Если height отсутствует, значение может быть вычислено
как произведение числа этажей на усреднённую высоту одного этажа (обычно
3–3.5 метра).
В MapLibre GL JS визуализация высот реализуется через слой типа
fill-extrusion. Этот тип слоя предназначен для построения
объёмных объектов на основе 2D-полигонов.
Базовая структура добавления слоя:
map.on('load', () => {
map.addLayer({
id: 'buildings-3d',
source: 'composite',
'source-layer': 'building',
type: 'fill-extrusion',
minzoom: 14,
paint: {
'fill-extrusion-color': '#aaa',
'fill-extrusion-height': 10,
'fill-extrusion-base': 0,
'fill-extrusion-opacity': 0.9
}
});
});
В этом примере высота задана фиксированным значением, что подходит только для тестирования или схематичных представлений.
Реалистичная визуализация требует использования свойств данных. Векторные тайлы позволяют обращаться к атрибутам через выражения.
Типовой подход:
'fill-extrusion-height': ['get', 'height']
Если данные не унифицированы, используется резервная логика:
'fill-extrusion-height': [
'case',
['has', 'height'],
['get', 'height'],
[
'*',
['to-number', ['get', 'building:levels']],
3
]
]
Такая конструкция обеспечивает гибкость при неоднородности исходных данных.
Некоторые здания начинаются не от уровня земли. Для корректного
отображения используется свойство fill-extrusion-base.
'fill-extrusion-base': [
'case',
['has', 'min_height'],
['get', 'min_height'],
0
]
Это позволяет визуально отделить здания на платформах, парковки на нижних уровнях и сложные архитектурные конструкции.
3D-здания не должны отображаться на всех уровнях масштабирования. Это связано как с производительностью, так и с читаемостью карты.
minzoom: 15
На низких зумах используется упрощённая 2D-геометрия, а при приближении активируется экструдированная модель.
Дополнительно применяется плавное появление высот:
'fill-extrusion-height': [
'interpolate',
['linear'],
['zoom'],
14,
0,
15,
['get', 'height']
]
Это создаёт эффект «вырастания» зданий при увеличении масштаба.
Высота может влиять не только на геометрию, но и на визуальные характеристики. Часто используется градиентное окрашивание:
'fill-extrusion-color': [
'interpolate',
['linear'],
['get', 'height'],
0, '#d9d9d9',
50, '#a6a6a6',
150, '#6b6b6b',
300, '#3d3d3d'
]
Такой подход позволяет мгновенно оценивать плотность и высотность застройки без анализа числовых значений.
Данные в реальных наборах редко бывают идеальными. Часто встречаются строки, отсутствующие значения или нестандартные единицы измерения.
Для очистки используется приведение типов:
['to-number', ['get', 'height'], 0]
Также возможна обработка значений с единицами:
[
'to-number',
['slice', ['get', 'height'], 0, -1],
0
]
(например, удаление суффикса “m”)
Наиболее распространённый практический сценарий — комбинирование
height и building:levels.
'fill-extrusion-height': [
'case',
['has', 'height'],
['to-number', ['get', 'height']],
[
'*',
['to-number', ['get', 'building:levels']],
3
]
]
Такая модель позволяет покрыть большую часть городских данных без ручной доработки.
Высота зданий становится особенно выразительной при включённом наклоне карты:
map.setPitch(60);
map.setBearing(-20);
В этом режиме экструдированные здания взаимодействуют с перспективой камеры, создавая эффект городской сцены.
Дополнительно может использоваться слой земли или DEM-данные для согласования высот зданий с рельефом.
Отрисовка большого количества 3D-объектов требует оптимизации:
minzoom для слояВ MapLibre GL JS рендеринг выполняется через WebGL, поэтому ключевым фактором становится баланс между детализацией и количеством полигонов.
map.addLayer({
id: '3d-buildings',
source: 'composite',
'source-layer': 'building',
type: 'fill-extrusion',
minzoom: 15,
paint: {
'fill-extrusion-color': [
'interpolate',
['linear'],
['get', 'height'],
0, '#e0e0e0',
100, '#b0b0b0',
300, '#707070'
],
'fill-extrusion-height': [
'case',
['has', 'height'],
['to-number', ['get', 'height']],
[
'*',
['to-number', ['get', 'building:levels']],
3
]
],
'fill-extrusion-base': [
'case',
['has', 'min_height'],
['to-number', ['get', 'min_height']],
0
],
'fill-extrusion-opacity': 0.85
}
});
Этот слой объединяет основные техники: извлечение атрибутов, резервные вычисления и визуальную дифференциацию по высоте.
В реальных городских наборах значительная часть зданий не содержит высоты. В таких случаях применяются стратегии:
Подобные подходы позволяют сохранить целостность 3D-сцены даже при фрагментарных данных.