Рельеф и места

Рельеф — это не просто «гора из шума»: под ним настоящие высоты конкретного места на Земле, настоящая карта земного покрова (лес, луг, поле, вода) и настоящие дома, дороги и провода из OpenStreetMap. Можно взлететь на одном из встроенных мест или ввести координаты — и полетать там, куда данные вообще дотягиваются.

Встроенные места

МестоЧто этоСтарты
ongudaiАлтай, долина Урсула у Онгудая, хребет с перевалом Каянча (полёты с 1980-х)южный склон у Онгудайского ретранслятора, 1870 м, курс 151°
askarovoБашкирия, хребет Биягода у Идяш-Кускарово (дельтадром, Чемпионат России 2025)запад у верхнего лагеря 294°, восток 94°, южная вершина 285°
aushkulБашкирия, озеро Аушкуль: гора Ауштау («пупырь») и хребет у СтаробайрамгуловоАуштау восток 119°, Ауштау юг 170°, хребет запад 273°
altaiМанжерок, Малая Синюха (дополнительное место)3 старта

Источники и допущения по каждому месту — в _sources_doc конфига места, например configs/locations/ongudai.json.

Полёт по координатам

Кроме встроенных мест, можно ввести любые координаты (широта, долгота) на карте выбора места — рельеф и карта поверхности подгружаются по сети:

terrain.load_location_latlon(43.25, 42.45, 40.0)   # lat, lon, размер стороны в км
await terrain.loaded

Карта выбора точки рисуется отмывкой (hillshade) прямо из тех же тайлов высот, что грузятся для полёта — без внешних картографических сервисов и ключей (scripts/terrain/map_picker.gd).

Источники высот

Для встроенных мест высоты — Copernicus DEM GLO-30 (разрешение 1″, ≈30 м, облачный GeoTIFF, бесплатно, без ключа): лучшее открытое качество, новее и чище SRTM. Данные конвертируются в плоский формат заранее (tools/terrain/fetch_dem.py), в игру попадают уже готовым слоем.

Для рантайм-мест (по координатам) — AWS Terrain Tiles (Mapzen/Tilezen): на суше в основе тот же SRTM (≈30 м), для отдельных регионов точнее (Европа — EU-DEM, США — 3DEP 10 м, выше 60° с. ш. — ArcticDEM). Открытый HTTPS без ключа и без лимитов, PNG-тайлы декодирует сам движок.

И Copernicus, и SRTM — модель поверхности (DSM), а не земли (DTM): в лесу «высота» — это верх крон (+15…25 м), на опушках и вырубках получаются ступеньки высотой с дерево. Поэтому детальный слой слегка сглаживается (σ = 0,8 клетки), а 3D-деревья утоплены в поверхность. Открытых моделей без леса для Алтая нет: FABDEM лицензирован под CC-BY-NC (не подходит для некоммерческого, но свободно раздаваемого проекта), национальные лидарные DTM закрывают только отдельные страны.

Каждое встроенное место хранит два вложенных слоя высот: детальный (40 км, шаг 25 м) и фоновый (160 км, шаг 100 м, Terrarium); узлы выровнены, на стыке нет ступеньки. Загрузка Алтая — 0,2–0,3 с.

Карта земного покрова

Класс поверхности (лес, луг, пашня, кустарник, скалы, вода, застройка, снег) — из ESA WorldCover 2021 (10 м, лицензия CC-BY 4.0). Из этой же карты берётся и цвет земли, и то, где стоят деревья, и сила источников термиков — три вещи из одного файла. fetch_landcover.py читает только нужные тайлы COG (HTTP range-запросы, без GDAL) и записывает класс узла как моду 3×3 подвыборок.

Дополнительно для детального слоя строится маска «деталь 10 м» (два канала: R — доля леса, G — доля воды в клетке 10 м): по ней кромка леса и берега рек выглядят гладкими, а не «лесенкой» из клеток 25 м. Вода в этой маске дополнена реками, каналами и ручьями из OpenStreetMap (ширина по типу: река 25 м, канал 6 м, ручей 4 м) и озёрами (полигоны OSM). Ручьи уже самой клетки в шейдере остаются берегом, а не сплошной водой; реки и каналы — сплошная вода. Данные всей локации, включая эту маску, — не больше 15 МБ.

Для рантайм-мест (по координатам) этой маски нет — вода определяется классом WorldCover, как раньше; если нет ни сети, ни данных — запасная процедурная карта по высоте, уклону, экспозиции и шуму (SurfaceClassifier), той же формы, что настоящая.

OSM-объекты: дома, дороги, провода, заборы

Для встроенных мест поверх рельефа стоят настоящие объекты из OpenStreetMap (data/osm/<id>.json, © OpenStreetMap contributors, лицензия ODbL): дороги (лента по рельефу, шаг 12 м на главных / 20 м на прочих, видимость 25 км / 4 км), здания (коробки стен + крыша, по контуру из OSM), линии электропередачи (решётчатые опоры 110 кВ / столбы 10 кВ, провод — парабола с провисанием 3 % пролёта, реальной толщины 2 см, но не тоньше пикселя; вблизи — линия, дальше 500 м не рисуется — как в жизни), заборы у посадочных площадок. С проводами есть столкновение.

Реки и озёра не рисуются из OSM отдельно — вода уже есть в раскраске рельефа (маска 10 м выше); данные OSM о воде лежат в файле и при желании terrain-модуль может заменить ими маски рек, построенные по стоку. Данные OSM выгружаются через Overpass API (tools/osm/fetch_osm.py) и хранятся в репозитории, а не запрашиваются игрой в реальном времени.

Для рантайм-мест (по координатам) OSM-данных нет — ставятся только ветроуказатели на стартах, без домов, дорог и проводов.

Вода

Класс «вода» задаёт не только цвет, но и поведение: над водой источники термиков слабые (0,05 из 1 по силе, против ≈0,87 у ровного поля). Визуально вода реагирует на ветер: в штиль — зеркало, к скорости ветра ≈ полная шероховатость («матовая рябь») — шероховатость и направление нормалей ряби идут поперёк ветра; в пятнах порывов рябь темнее («кошачьи лапы» — меньше отражённого неба), против солнца искрится. Со стороны, откуда дует ветер, вода гасится сушей и остаётся гладкой полосой (4 выборки маски воды против ветра). Вдоль берега — тонкая полоса мокрого грунта. Подробнее о ветре на воде и суше — на странице Облака и тени и в разделе трав ниже.

Лес и растительность

Три плана леса с высоты:

  1. Полог рельефа (на самом классе «лес» в шейдере) — кроны-ячейки Вороного ≈6 м, освещение по солнцу, тень от соседней кроны, тёмные просветы; на расстоянии, где отдельная крона мельче пикселя, — плавный переход к среднему тону полога с пятнами древостоев.
  2. Средний план (0,35–3,5 км) — билборды деревьев из атласа импостеров на сетке 12 м.
  3. Ближний план (до ≈0,7 радиуса видимости моделей) — 3D-модели: 5 пород (берёза, лиственница, кедр, ель, сосна) × 3 LOD, порода зависит от высотного пояса и экспозиции склона (ель на северных, сосна на южных сухих), локация может переопределить веса пород.

Деревья стоят только там, где маска «деталь 10 м» показывает лес (доля ≥ 0,5), и не стоят в воде (доля воды маски < 0,35). У кромки леса деревья гуще и меньше утоплены — опушка выглядит объёмнее, а не обрывается стеной. Просеки (дороги, коридор ЛЭП, здания, поля посадок) вырезают деревья явной маской (WorldClearings) — ни модель, ни импостер туда не попадают.

Травинки вокруг камеры, их прореживание и качание от ветра — отдельная механика, читайте docs/guide/vegetation.md (параметры и графические пресеты) и раздел «Ветер на земле» ниже.

Как рельеф строится и подгружается

Меш. Каждый слой высот режется на чанки; у всех чанков слоя общие плоские сетки нескольких LOD (шаг 1, 2, 4… клетки) — высоту в них добавляет вершинный шейдер выборкой из текстуры высот, поэтому построение меша мгновенное. LOD переключается по расстоянию камеры до чанка; щели между уровнями закрывает «юбка». Коллизии как таковой нет — полёт и посадка используют функцию height_at (билинейная интерполяция самого детального слоя, покрывающего точку; ≈1,6 мкс на вызов).

Рантайм-загрузка (полёт по координатам) не подвешивает главный поток: тайлы высот и карты покрова качаются через HTTPRequest в фоновых потоках, сборка меша, деревьев и травы идёт по кадрам в рабочем потоке, пока экран загрузки показывает этапы и долю прогресса. На высоких широтах пиксель веб-меркатора мельчает как cos(широты) — уровень тайлов автоматически понижается, чтобы сетка не раздувалась (например, у Гренландии на 72° с. ш.).

Ошибки возвращают в меню с понятным сообщением: нет связи с сервером рельефа, для точки нет данных (тайл 403/404), точка — море (высота ниже уровня моря без карты покрова с сушей рядом), сервер рельефа не отвечает (таймаут по неизменному прогрессу).

Границы модели

  • Разрешение. Высоты — 25 м у встроенных мест (30 м у рантайм-мест), карта покрова — 10 м у детальной маски / 25 м у общей карты классов. Мельче этого рельеф ничего не различает — камни, тропинки и отдельные кусты на карте не «настоящие», а процедурный рисунок по статистике.
  • DSM, а не DTM. Высота в лесу — верх крон, а не земля под ними; посадка в лес — это столкновение с кронами, а не спуск сквозь них до земли.
  • Из OSM берётся не всё. Рисуются дороги, здания, ЛЭП и заборы у посадок; реки и озёра берутся не из OSM-геометрии, а из общей карты воды (маска 10 м/класс WorldCover). Другие объекты OSM (мосты, малые формы, дворы) не отображаются.
  • Рантайм-места беднее встроенных: без OSM (нет домов, дорог, проводов, заборов), без маски воды 10 м (вода — только по классу WorldCover), без специально расставленных посадочных площадок — только выбранная точка и курс вниз по склону.
  • Бюджет данных — не больше 15 МБ на встроенное место (высоты + карта покрова + маски), поэтому часть деталей (например, ширина ручья по тегу OSM) намеренно не учитывается.
  • Термики завязаны на ту же карту, что и цвет земли: если WorldCover ошибся с классом (типичная ошибка спутниковой классификации — спутать пойму с лесом), это отражается и в термиках, и в картинке одинаково — модель не «подглядывает» правильный ответ отдельно от того, что видно пилоту.

Что рассматривали и почему так

  • Тайлы карты для экрана выбора места. Стандартные тайлы tile.openstreetmap.org по политике использования — только для умеренного, некоммерческого трафика с атрибуцией и без массовой предзагрузки; для распространяемой игры без гарантированного лимита это не подходит. Платные сервисы (MapTiler, Thunderforest) потребовали бы зашить API-ключ в открытый код. Свой сервер тайлов из OSM — вариант на будущее, но требует инфраструктуры. Выбрана отмывка рельефа (hillshade) из тех же тайлов высот, что и так нужны для полёта: без внешних сервисов и ключей, горы и долины читаются пилоту лучше дорог.
  • DEM для рантайма. Coperniсus DEM лучше по качеству, но в игру его для рантайм-точек по всему миру не зашить (весь земной шар — не 15 МБ). OpenTopography даёт удобный API, но требует ключ и ограничен по площади и числу запросов в сутки — не годится для игры у случайного пользователя. AWS Terrain Tiles — открытые PNG-тайлы без ключа и без лимитов, декодируются самим движком; качество немного ниже Copernicus (местами ступеньки SRTM), но для полёта достаточно.
  • DTM без леса не нашли с подходящей лицензией (FABDEM — CC-BY-NC), поэтому вместо попытки убрать лес из высот выбрано простое сглаживание + утопление 3D-моделей деревьев в поверхность.
  • Одна карта на три задачи. Цвет земли, расстановка деревьев и сила термиков раньше могли бы жить в трёх разных структурах; решили держать одну карту поверхности как единственный источник истины — это и проще, и не даёт картинке разойтись с моделью термиков.

Подробнее

Ветер по воде: штиль, порывы 3 и 6 м/с

Костёр у лагеря на старте, дым сносит реальный ветер

Место Алтай: реальный рельеф долины Урсула