27 April 2015

Визуализация данных OpenStreetMap в 3D налету с помощью Unity3D

Game developmentOpenStreetMapC#Unity3D

Предыстория


image
Некоторое время назад, в связи с наличием свободного времени, я задумался над применением карт для решения каких-либо интересных и нестандартных задач. Одна из идей, которая меня заинтересовала, была идея применения карт для рендеринга мира в игровом движке c возможностью интерактивного взаимодействия: разрушения Макдональдсов в выбранном городе, локальный апокалипсис у соседей в огороде и тому подобные приятные, но только в случае виртуального мира, мелочи.
Однако несмотря на примитивность идеи, не было найдено каких-то готовых решений под сформулированные мной условия:
  • Открытый исходный код
  • Реал тайм рендеринг мира в игровом движке
  • Поддержка основных платформ (mobile, web, desktop)
  • Желательно C# как основной язык разработки


Конечно, идея рендеринга карт в 3D абсолютно не нова и есть готовые решения как с открытым кодом, так и проприетарные (ни в коем случае не претендую на полный список):

Как правило, подобные решения используют OpenStreetMap данные для рендеринга мира в 3D, т.к. данная возможность в картах есть и активно развивается. Также огромным плюсом OSM является возможность скачать полный дамп данных всей планеты или какой-то определенной части/города (например geofabrik или metro-extracts), притом без жестких лицензионных ограничений.

ActionStreetMap


Таким образом, решено было начать разрабатывать свой проект с нуля под названием ActionStreetMap, что, по идее, должно напоминать о природе исходных данных и способе их использования. В качестве игрового движка был выбран Unity3d, что абсолютно неудивительно из-за последнего условия (язык разработки C#) и развитого сообщества, поскольку это первый мой опыт в области разработки игр.
image
Проект стартовал больше года назад и находится в активной стадии разработки, даже несмотря на то, что я по-прежнему единственный разработчик. Ниже перечислены основные возможности, которые реализованы на текущий момент:
  • Flat shading стиль
  • Рендеринг основных объектов OSM (здания, дороги, заборы, деревья, реки, парки, POI...)
  • Использование SRTM данных для создания карты высот
  • Автозагрузка карт с сервера OSM и SRTM данных с сервера NASA
  • Оффлайн карты (поддерживается импорт из основных форматов данных OSM – pbf, xml, o5m)
  • Поддержка примитивного поиска мест в оффлайн режиме
  • Поддержка модификации некоторых объектов (экспериментальная возможность)
  • Асинхронная загрузка всего и всея (с использованием Reactive Extensions)
  • Возможность кастомизации

На первом и последнем пунктах хотелось бы остановиться по-подробнее, несмотря на то, что я не ставлю цели описать внутреннее устройство реализации проекта в данной статье.

Flat shading


После экспериментов с текстурами зданий и unity terrain было решено отказаться от попытки срендерить «правдоподобный» город. Причины тривиальны:
  • Отсутствие реальных данных о фасадах зданий и других объектах (текстура хрущевки на фасаде Рейхстага смотрится забавно поначалу, но со временем начинает напрягать..)
  • Производительность

В результате был выбран подход «с треугольниками», хотя возможность срендерить что-то свое в другом стиле по-прежнему присутствует.

Кастомизация


При знакомстве с OSM картами, меня заинтересовала идея применения CSS подобного языка для описания какие объекты должно быть срендерины и как. В результате, подобный подход с некоторыми особенностями был использован и в ASM. Например, здания частично определяются следующими правилами:
area[building]                      { builder: building;  height:12; min_height: 0; levels: 5; fill-color:gradient(#c0c0c0, #a9a9a9 50%, #808080); facade-builder:empty; material:Materials/Buildings/Building; }
area[building:levels]               { height: eval(num(tag('building:levels')) * num(3.2)); }
area[min_height]                    { min_height: eval(num(tag('min_height'))); }
area[building:height]               { height: eval(num(tag('building:height'))); }
area[building:height][roof:height]  { height: eval(num(tag('building:height')) - num(tag('roof:height'))); }
area[building:cladding=brick]       { fill-color:gradient(#0fff96, #0cc775 50%, #066139); }
area[roof:material=brick]           { roof-color:gradient(#0fff96, #0cc775 50%, #066139); }

Этот подход убрал логику парсинга правил из C# классов, а в сочетании с Composition Root и Dependency Injection паттернами, используемыми в проекте, сильно упростил задачу кастомизации рендеринга OSM объектов и добавил возможность создания «тем» (например, зимняя, летняя тема и т.п.), которые можно менять без перекомпиляции исходного кода.

Исходники


В настоящий момент доступны исходники демо проекта в Unity Editor, а также web build с небольшой частью карты Москвы.
Сам фреймворк пока не на github, но при заинтересованности unity сообщества в его развитии может быть опубликован.
Tags:грабить корованыгуси
Hubs: Game development OpenStreetMap C# Unity3D
+25
29.5k 124
Comments 17