Дмитрий Нищета
разработчик
из команды веб-карт
Евгений Родыгин
разработчик
из команды веб-карт
Небо
Продолжаем делать наши карты всё более реалистичными, а сценарии исследования — всё более увлекательными. Уже сделали рельеф, хилшейд, глубины и стопку иммерсивных моделей, а теперь на карте появился наклон, с которым можно увидеть туман и почти настоящее голубое небо.
Некоторые иммерсивные детали в карте, например, 3D-модели, раскрывают всю красоту при детальном рассмотрении. Для этого нужно позволить пользователю свободно перемещать и наклонять карту.
Если с перемещением никаких вопросов у нас не было, то большой наклон карты изначально не проектировали. И при попытке наклонить карту больше чем на 45° мы видели картинку, как на этом скриншоте ↓
В первую очередь нам нужно было отодвинуть край карты, за которым нет детальных данных. И для этого пришлось углубиться в механику работы наклона.
Как работает наклон
Сначала разберёмся, что такое наклон, как он влияет на карту и почему мы видим её край на предыдущем скрине. Нам понадобится немного математики.

Рассмотрим общий случай: дана горизонтальная плоскость и некоторый наблюдатель, которого мы будем называть камерой. При таких условиях наклон — это угол между перпендикуляром, опущенным из камеры на плоскость, и её направлением.
Из камеры видно область X, которую можно выразить через угол: X = H x tg (α). При увеличении угла наклона будет увеличиваться и размер видимой области, а при α = 90° размер области X равен бесконечности. Также обратим внимание на первую производную по α: X' = H/(cos2(x)), из которой можно сделать вывод, что даже малое приращение угла α сильно увеличивает видимую камерой область X.

Из-за этого мы не можем увеличить наклон без значительного увеличения количества отображаемой геометрии.
Теперь посмотрим, как работает видимая область нашей карты. Для определения области 3D-пространства, которую видит камера, используем view frustum (это усечённая пирамида видимости — она показывает форму региона, который можно увидеть и отрисовать перспективной камерой).
Усечённая пирамида видимости — это то, что лежит между ближним и дальним планами
Далее проецируем view frustum на плоскость карты, чтобы определить видимую область.
Нам нужно заполнить видимую область данными. В картографии данные разбиты на тайлы. Каждый тайл — это квадрат конкретного размера в тайловой сетке. Получается, нам нужно показать те тайлы, которые пересекаются с видимой областью.
Здесь размер тайла — 1,2 км²
Как мы уже выяснили, увеличение наклона приводит к быстрому увеличению размера видимой области. Эту область нужно заполнить тайлами. Но мы не можем загружать и показывать неограниченное число тайлов, потому что их нужно скачать, обработать и нарисовать на устройстве пользователя. Раньше карта устанавливала ограничение на размер видимой области, что позволяло заполнять её при максимальном наклоне 45°.

Теперь, когда мы понимаем, как наклон влияет на карту, мы можем перейти к поиску решения.
Поиск решения
Увеличим максимальный наклон. Мы начали исследования с того, чтобы увеличить максимальный наклон карты и снять ограничения видимой области. Мы подтвердили наши опасения и увидели несколько новых проблем:
  1. Нужно нарисовать сильно больше тайлов, чем при максимальном наклоне 45°. Даже на производительных устройствах карта теряет отзывчивость.
  2. Объекты тайлов, которые расположены далеко от камеры, становится плохо видно, так как их слишком много и они накладываются друг на друга.
У нас появилась идея, которая могла помочь решить обе эти проблемы.

Используем тайлы меньшего зума. Идея заключается в том, чтобы по мере увеличения расстояния от камеры использовать тайлы меньшего зума. В таких тайлах меньше данных, и они покрывают большую площадь, что должно помочь решить проблему падения производительности при увеличении наклона.
Компактные по размеру данных тайлы меньше зума — ближе к горизонту
Попытка применить этот подход создала проблему, которую не получилось решить за предсказуемое время: на границе между тайлами разных зумов стали видны разрывы данных. К тому же, использование тайлов меньшего зума на отдалении не помогло полностью решить проблемы с производительностью, а доводить этот вариант до релиза было очень дорого.

Стало ясно, что внедрить наклон для карты в общем случае пока не получится.

Ограничим область применения наклона. Мы решили попробовать ограничить применение большого наклона. Таким образом, карту можно наклонить на угол более 45° только при ближнем зуме. Это позволит рассмотреть детали карты и избежать проблем с большим наклоном на дальнем зуме.
Осталась только одна проблема, которая не даёт нам использовать большой наклон в продукте — то, как выглядит карта вдали: пустота и нечитаемые здания.
Эту проблему призван решить туман, а ещё небо — они заполнят эту пустоту и заодно скроют нечитаемые объекты.
Небо
При большом наклоне становится виден край карты, а над ним простирается полотно светло-бежевого цвета, которое никак не напоминает небосвод. Поскольку нам хочется идти в сторону большего реализма, то решили добавить небо.

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

Самое примитивное решение — это залить всё однотонным цветом, что мы в итоге и сделали. Дёшево, сердито, но эффективно.
В результате мы почти достигли нужного результата, но выглядит слишком примитивно. Начали работать с туманом!
Туман
У тумана на карте есть две цели. Первая — он должен скрыть некрасивую границу тайлов. Вторая — потенциально оптимизировать то, что он скрывает: либо совсем скрывать все здания за ним, либо рисовать их сильно менее детальными.

Для создания тумана первым делом попробовали смешать цвета объектов с цветом тумана в зависимости от расстояния от этих объектов до камеры. Как функцию распределения интенсивности тумана мы выбрали обычную линию — это самый быстрый вариант. В играх часто используют нелинейные зависимости, потому что они дают более реалистичное распределение, но в картах нам пока это не нужно.
Получается, с какого-то расстояния туман становится видимым и при удалении от камеры он постепенно заслоняет собой объекты. Немного поигравшись с границами на близком зуме, мы получили примерно такую картинку.
Слева — маска, по которой применяем туман, а справа — как это выглядит в итоге. Мы здесь немного увеличили настройки тумана, чтобы его было лучше видно
В этом подходе есть три проблемы. Две очевидные и одна неочевидная.
  • Туман не влияет на небо, потому что оно не учитывается в глубине при рендеринге. Иными словами, мы видим слишком жёсткий переход на горизонте.
  • Иконки и некоторые другие 2D-объекты явно выбиваются из общей картины, но к их цвету нельзя просто применить цвет тумана, так же как к остальным объектам, поскольку они рисуются поверх всех остальных слоёв.
  • Неочевидная проблема: если мы уменьшим масштаб карты, то монотонный туман окутает вообще всё.
Первую проблему мы решили, добавив в шейдер неба информацию о тумане, а ещё учли цвет неба при применении тумана ко всем объектам на карте.
Со второй проблемой разобрались, снизив прозрачность иконок по тому же закону, по какому мы затуманиваем другие объекты. На наш взгляд, получилось довольно гармонично. Лишние иконки не мешают при навигации по карте, а читаемость того, что находится вблизи, не пострадала.
А вот неочевидная проблема заслуживает отдельного параграфа.
Туман на разных масштабах
Предположим, мы настроили расстояние, которое нас устраивает и на котором растёт интенсивность тумана. И сделали это на близком масштабе. Картинка выглядит хорошо. При вращении камеры тоже не возникает проблем. Казалось бы, всё готово. Но это не так. Стоит отдалить камеру, уменьшив мастштаб, как туман окутывает весь экран. Мы этого совсем не хотим — у нас всё-таки карта, а не Сайлент Хилл. Нам в первую очередь важна удобная навигация.

Вот как эта проблема выглядит сбоку.
Всё, что находится за пределами сферы, полностью скрыто в тумане. Слева — вид, который мы получаем на предыдущих скринах. А справа расстояние до всех объектов настолько велико, что туман даёт 100-процентную заливку
Изначально все наши идеи крутились вокруг более сложной функции тумана. Наиболее многообещающим вариантом казалось снижение интенсивности в конусе под камерой. Но мы не будем приводить все неудачные попытки решить эту проблему.

В итоге пришли к очень простому варианту, который полностью покрыл наши требования: мы привязали распределение тумана к расстоянию до точки вращения камеры. Это выглядит примерно так.
Что получилось
В итоге получилось реализовать продуктовые требования: теперь карты на 2gis.ru можно рассматривать под большим наклоном. Особенно приятно, что мы смогли добиться желаемого эффекта и не потерять производительность карты.
Сейчас большой наклон и туман работает на 2gis.ru, а в будущем опубликуем их в нашем MapGL JS API. И не забудем о мобильных приложениях. Пользователи часто об этом просят — уже делаем.
Нажимая кнопку «Комментировать», вы принимаете условия Лицензионного соглашения и даёте ООО «ДубльГИС» согласие на обработку персональных данных на условиях и в целях, определённых «Политикой конфиденциальности».