Можно было делать очень долгое и интересное введение в тематику антитеррористических мероприятий на объектах критической инфраструктуры, но это не является профильным направлением Хабрхабра, поэтому попытаюсь сделать краткую инъекцию, не отягощенную терминологией.
И всё же, для тех, кто решит пропустить длинное введение, ищите подзаголовок «Что же с виртуальной реальностью?».
Кому интересны только итог и «Best practice», тогда сразу в «Заключение».
Обновление от 18.12.2017: добавлено видео, ускоренное в 4 раза. Ссылка на видео со звуком будет доступна позже конце статьи.
Что за проблема такая?
Конкретно в данном случае, мы говорим о специалистах по охране ядерных установок. Глобально десятки или даже сотни тысяч специалистов в ожидании первичного или очередного, обучения, а учебных и тренировочных центров не хватает (более подробно ниже под спойлером).
Задача: Нужен виртуальный объект для визуализации ошибок при проектировании систем охраны, представления лучших практик в проектировании, отработки различных сценариев и практических навыков повседневной эксплуатации средств безопасности.
P.S. — задача конечно не для конечного продукта, но для демонстрации рабочей технологии на крупнейшей в области ядерной безопасности конференции.
Скриншоты виртуального полигона и класса с аватаром
Подробнее об ядерных угрозах
Практически с самого появления мирного атома, проблема террористов, криминала и внутренних нарушителей является одним из основных топиков сразу после обеспечения технической безопасности эксплуатации — это та самая, с которой связаны Чернобыльская катастрофа и авария на Фукусиме.
Наиболее остро данный вопрос конечно же стоит в странах, которые обладают ядерным оружием, так как они должны заботиться ещё и сохранности стратегически важных материалов прямого использования — таких, которые в течении короткого промежутка времени могут быть обращены в импровизированное ядерное взрывное устройство усилиями нескольких специалистов без продвинутых военных технологий.
Именно в РФ и США существуют большие полигоны для испытания средств охраны таких особо важных объектов и, конечно же, обучения специалистов. В большинстве случаев они являются на половину закрытыми для посещения, а значит обмен информацией с международным сообществом хоть и анонсируется как открытый, является очень ограниченным.
Не смотря на все угрозы для мирного атома, он очень активно внедряется в странах третьего мира и просто развивающихся странах. На сегодня в эксплуатации находится более 1000 атомных установок различного назначения и различной категории и их количество продолжает расти. Центров по подготовке специалистов, в свою очередь, так мало, что можно их пересчитать на пальцах, и их возможностей не хватает для охвата всех нуждающихся. К тому же, безопасность является обязательным пунктом для пуска реактора, но при этом никогда не датируется государством, поэтому при капиталистическом строе — является всегда только расходной частью, которую всегда пытаются оптимизировать.
Умножая и так не маленькие расходы на большую текучку кадров и невозможность использовать реальные объекты для обучения и тренировки будущих специалистов, получаем набор проблем в образовательных и тренировочных подходах, которые длятся последние 20 лет и, не смотря на деньги всего мира (а МАГАТЭ является частью ООН, где в прямом смысле распоряжаются деньгами всего мира на улучшение жизни человечества), продвинутого решения предложено не было до этого года.
Альфа версия без вложений
Чтобы показать всю красоту и возможности использования виртуальной реальности, мне понадобилось следующее:
Я, инженер по эксплуатации ядерных установок, без образования в области информатики. 30 лет, опыт работы с 3D's Max 1,5 года — 15 лет назад, 4 месяца экспериментов с Unity3D с небольшим билдом под Windows в виде простенькой модели ядерной установки с возможностью погулять по территории и парочкой фич в виде взаимодействия со средой — её видео-презентация на 2 минуты;
2 календарных месяца времени без других обязанностей на рабочем месте и полная свобода действий по поводу графики, кода, функционала и т.д.;
только что приобретённый для этого проекта Oculus Rift + Touch;
3D's Max 2014;
Substance Painter;
Unity 2017;
0.0$ бюджет на модели, скрипты, плагины или текстуры.
Что же с виртуальной реальностью?
Так как у меня не было никакого опыта разработки игр или приложений (кроме тех упомянутых выше 4-х месяцев), то делал я всё по логике и предыдущему небольшому опыту.
Мой план был следующим:
2 дня на составление ТЗ для самого себя;
1 неделя на изучение самих очков (включая изучение 6 игр в комплекте с тач контроллерами) и Oculus Rift's Unity Sample Framework;
2 недели на подготовку моделей;
1 неделя на текстурирование;
3 недели на построение уровня из моделей, физики, интерфейса пользователя и всего всего, что нужно для того, чтобы успешно собрать билд и демонстрировать его на конференции не из редактора Unity;
1 неделя на тестирование и устранение возможных багов.
Сказать, что я был слишком оптимистичен, не сказать ничего. Конечно же, данного плана в реальности не удалось придерживаться, но последовательность была соблюдена (в основном благодаря 16 часовому рабочему дню и 6 дневной рабочей неделе).
ТЗ
Так случилось, что ровно перед началом разработки этого проекта, состоялся разговор с потенциальными заказчиками. Часть ТЗ была взята из интересующих их моментов, остальная часть состояла из того, что я разрекламировал как уже имеющиеся решения (ничего конечно ещё не было).
Что мы хотели:
Реалистичные сложные объекты с PBR текстурами и соответствующим освещением, чтобы от увиденного у мозга не возникало «картунных» ассоциаций;
Движение персонажа на основе Locomotion, так как необходимо было выполнять задачи по осмотру протяжённых участков и поиску заранее неизвестных мест;
Носимый инвентарь с мультиметром, лестницей, запасными частями и т.д. — обычный набор техника или инженера на участке периметра;
Устанавливаемые дополнительно элементы по желанию пользователя: камеры, вышки охраны, извещатели и т.д. с дальнейшей настройкой;
Визуализация зон обнаружения извещателей различного принципа действия по запросу пользователя;
Реалистичное взаимодействие с объектами в стиле «возьмите штекер — воткните его в разъём на приборе — отъюстируйте руками прибор до нужного уровня сигнала на мультиметре — отключите всё, закройте крышки и проверьте работу прибора»;
Комфортно читабельная текстовая, аудио или видео информация в очках в нужный для пользователя момент.
Oculus Rift + Touch
Так как до этого момента я ни разу не надевал очки виртуальной реальности (даже кардбокс), то понятия не имел чего ожидать внутри. До этого я полагал, что виртуальная реальность всё ещё далека от комфортного использования и каких-либо удовлетворительных ощущений от её использования в играх или приложениях.
На мой взгляд, я ошибся. Уровень графики, скорость реакции и удобство контроллеров произвели на меня более чем положительное впечатление. Во время тестирования Dead&Buried, Robo Recall и Toy Box я уже мысленно заимствовал понравившиеся мне элементы взаимодействия пользователя с меню и окружающим миром.
В целом, всё казалось очень лёгким для понимания и логичным. Этот эффект длился ровно до того момента, пока несколько человек из окружения шефа не попробовали поиграть. Оказалось, что не все понимают игровую логику как я: многие люди боялись нажимать кнопки или делали это хаотично без всякой логики и анализа результатов. Таким образом оказывалось, что через 10 минут игры в Robo Recall люди всё ещё не понимали откуда берётся оружие и как его перезарядить или телепортироваться в новое место. Это происходило не в 100% случаев, но больше половины терялось на долго, что окончательно их разочаровывало и они поспешно снимали «очки» даже не достигнув стадии «подташнивания».
На изучение фреймворка я потратил на неделю больше запланированного времени, так как… долго тупил.
Таким образом я пришёл к выводу, что мне обязательно нужна вводная сцена для обучения пользователя в спокойной обстановке, где он может потратить 5 минут на понимание той среды, в которой очутился, да и я заодно смогу поэкспериментировать с тем, что буду внедрять.
Моделирование и адаптация бесплатных моделей
На начало данного этапа в задумке было две сцены (в начале статьи два скриншота из этих двух сцен):
Учебный класс с курсом «молодого бойца» на 5 минут и меню перехода в следующую сцену, которое доступно после завершения тренировки.
Гипотетическая ядерная установка с очень детально прорисованными элементами охраны, так как это основная цель в данном проекте.
Создание моделей очень интересный процесс, но может длится вечно. Первую сцену я делал сам практически на 80%, и, потратив миллион времени на low-poly модели, понял, что не успею сделать хорошие модели за отведённое время.
Я решил найти максимум бесплатных моделей (неважно с текстурами или без) и адаптировать их, тем более что мне нужны были собственные развёртки для текстурирования (ниже поясню зачем).
Мне удалось найти за пару дней достаточно много подходящий моделей в различном формате, открывающихся в 3d's Max. Пригодились следующие сайты:
Были конечно же и другие, но часть ссылок не могу найти.
Основные проблемы при работе с готовыми моделями:
Закрытый стэк без возможности деактивировать ранее наложенные модификаторы типа TurboSmooth, MeshSmooth и т.д. Как итог, огромное количество ненужных полигонов.
Часто непредсказуемое поведение сетки при применение модификатора ProOptimizer. Итог аналогичен первому пункту плюс невозможность сделать низкокачественную модель для Unity LOD.
Хаотично перевернутые полигоны после преобразования Editable Mesh в Editable Poly. При этом сам Макс мог отображать всё правильно, а факт дефекта обнаруживался после импорта в Unity.
В этот момент я уже знал про LOD, но всегда думал, что это автоматический процесс. Правда оказалась коварнее, но было поздно. Модели с LOD =1 и =2 в итоге я сделал только частично и не обращая сильно внимания на их качество.
Первая сцена заняла намного больше времени, чем нужно было уделить. Во многом это была моя вина. Все элементы комнаты были стандартными офисными предметами, коих полным полно в бесплатном доступе, но почему-то часть из них я решил делать сам, за что поплатился лишней неделей работы. К тому же, их число не превышало 20 уникальных объектов на всю комнату, поэтому даже не оптимизированные модели подошли бы без всяких проблем.
Вторая сцена уже на 99% состояла из скачанных ранее моделей, но они были совсем не оптимизированы и их было несколько сотен.
Параллельно пришлось набивать шишки на подготовке к экспорту и импорту моделей в Unity. В «Заключении» обязательно выведу несколько советов.
Текстурирование
Если кратко, то это было долго, нудно и нервно. Всю историю с текстурами можно разделить на первую и вторую мои сцены.
Первая была сделана по принципу: один объект — один материал. Очень неэффективно, но позволяет добиваться невероятного реалистичного эффекта.
Вторая была сделана по принципу: 100 объектов — один материал.
В интернете можно найти очень немного вариантов работы с атласами, поэтому каждый придумывает свое колесо. Атлас текстур позволяет нам использовать один материал с текстурой в Unity сразу для множества объектов. Сразу оговорюсь, что для tiling'a — то есть для автоматического копирование куска текстуры на всю поверхность объекта, данный метод не подходит.
Мой рецепт ниже. Можно также использовать инверсию данного метода, возможно кому-то она покажется более приемлемой.
Так как Unity позволяет использовать 8к текстуры, а Substance Painter позволяет их создавать, то была выбрана именно эта программа.
Я решил что на каждый объект, в зависимости от его размера мне понадобиться текстура размером от 512х512 px до 2048х2048 px, а значит исходя из минимального размера на сторону в 8192 px поместиться 16 квадратов по 512 px. Отмечу сразу, что в ходе работы с Substance Painter'ом (SP) я пересмотрел свой подход и сделал один квадрат не 512х512, а 1024х1024, чуть ниже скажу почему.
Итак, создаём в 3d редакторе плоскость с сеткой полигонов 8х8.
Создаём новый материал и применяем его к нашей плоскости.
В модификаторе Unwrap UVW выставляем настройки так, чтобы наша виртуальная сетка на плоскости совпадала с сеткой в модификаторе, чтобы мы могли чётко видеть границу между разными текстурами, когда «разворачиваем» модель.
Экспортируем нашу плоскость как .fbx для импорта в SP
Открываем SP, создаём новый проект и добавляем в качестве low-poly модели нашу плоскость.
Создаём 64 папки и всем накладываем чёрные маски, при этом каждой накладываем белую маску на соответствующий папке полигон.
Создаём нужные текстуры, экспортируем их в нужном разрешении (я делал 8к) и импортируем в Unity, не забывая в настройках импорта разрешить использовать их как 8к.
Как работать с SP к счастью найти не проблема, потому что в сети очень много хороших туториалов, а в нашем случае нужны только базовые знания, для которых хватит учебных видео от фирмы разработчика SP.
В Unity Store были плагины, которые позволяли создавать атласы из имеющихся материалов автоматом без физического объединения предметов при runtime, и цена их была не выше 30-40 у.е., но у меня не было бюджета вообще, поэтому я делал с костылями и протезами.
Unity
За время работы над предыдущим проектом я приобрел небольшой опыт написания кода, используя Unity Script, который как бы С#. Знания, а тем более навыки, мои были ограниченны использованием различных циклов и отложенных функций. Часто мне необходимо было изменить или дополнить скрипты из того же фреймворка для Oculus Rift (OR), но как переписать защищенные переменные или функции я не знал, поэтому от некоторых идей приходилось отказываться на ходу или опять вставлять костыли, за которые нормальные программисты бы меня съели. Но как было, так было… время шло, нужно было рабочее, а не красивое.
Первое от чего пришлось отказаться — это «хватание» объектов одновременно двумя руками. Это можно было довести до ума фреймворком от Oculus, но разумнее было бы использовать совместимый с OR плагин для взаимодействия, в котором эта функция уже была осуществлена. К этому моменту я был уже знаком с родным плагином от Oculus, поэтому решил ничего не менять и не рисковать.
Вторым убийцей времени стали двери, ворота и т.д. — всё что крутиться на петлях и должно открываться за ручку. Я потратил день или два, чтобы забросить эту идею до более подходящего по времени момента. Остановился на варианте: коснулся рукой ручки — дверь открылась.
Третим убийцей стал «планшет», который был у пользователя на левой руке и использовался для инвентаря, информативных сообщений и т.д. Я хотел осуществить нажатие кнопок как в реальной жизни — касание к экрану, но это вызывало слишком много ложных кликов. Нужно было перерабатывать систему триггеров на кончиках пальцев, на что времени не было. Поэтому я добавил лазерную указку как в Oculus Home и установил взаимодействие на уровне нажатия на «триггер курка».
Четвёртым убийцей времени стало желание набирать пин-код нажатием кнопок, а не касанием к ним. Это выглядело очень круто: ты нажимаешь пальцем кнопку, она утапливается в корпусе и тогда только появляется цифра. Убираешь палец и кнопка всплывает обратно. Проблема была в том, что кнопки были посажена на Spring Joint и периодически физика Unity теряла их или они улетали и т.д. Я довёл эту фишка до рабочего состояния, но это стоило слишком много времени.
Спасибо миллиону триггеров и их простоте. Алгоритм детектирования взаимодействия пользователя с различными объектами и детектирования событий я очень быстро осуществил на базе коллайдеров и триггеров. Это может быть очень примитивно, но работает чётко и быстро, хоть и занимает много «места» в коде.
Нужен был инвентарь. Мне очень понравилась идея с носимым на руке устройством как в Toy Box. Что и было сделано в форме планшета, как я раньше уже упомянул. При этом планшет был на внутренней стороне левого предплечья. Руки были свободны и обзор ничего не закрывало, при этом быстро и удобно можно было осуществить любые действия в «игре». Правда для людей с маленьким ростом это оказалось совершенно неудобно, так как нужно было вытягивать руку слишком далеко от себя.
Всё должно было быть логично и интуитивно, и мне так всё и казалось. Помните я писал, что опыт наблюдения за другими игроками. Всегда помня о них, каждый новый элемент или вариант взаимодействия добавлялся с мыслью о самых «тугих» пользователях. Кстати, вторым наблюдением за другими пользователями стало то, что они почти никогда не читали сообщений на экране. Тогда я понял, что без голоса приятной девушки я не обойдусь.
Этим голосом стал голос генератора речи Win 10 и программа eSpeak. Это было бесплатно, быстро, понятно и даже очень милозвучно. Я записал в конечном итоге более 20 фраз и инструкций на английском языке, которые всегда сопровождали игрока и дополняли эффект присутствия.
Снова же, многие вещи можно было не добавлять, как например возможность нажатием пальца на выключатель включить или выключить свет в комнате или реально нажимать кнопки на устройстве для ввода ПИН кода. Но мне нужен был ВАУ эффект хотя бы в некоторых моментах. Для некоторых взаимодействий мне пришлось добавить коллайдеры на каждую руку аватара, они работали вместе с Avatar SDK и генерировали около 50 килобайт мусора каждый кадр. Из-за этого проверять приложение в редакторе было невозможно GC убивал весь фреймрейт и не давал оценить работоспособность приложения. В билде дела обстояли немного лучше.
Напишу тут же про свет в Unity. Всё шло неплохо, пока оказалось что создание lightmap для отдельных предметов не работает — видимо баг версии, а для запекания всего света требовалось 8 часов на просчёт! 8 часов, чтобы увидеть тестовый результат и начать запекать снова. При более низких настройках всплывало много артефактов из-за несоответствия разрешения текстуры и карт теней и т.д.
Весь свет у меня был «запеченный», поэтому проблем быстродействия из-за него мне не пришлось решать. От этой идеи я не отказался, так как иначе бы точно вышел за рамки нужных мне 90 fps.
В общем, я осилил внешний свет и меня устроил результат, но проблема появилась внутри здания. Я так не выяснил причины, но внутри здания происходило неизвестно что, было море артефактов и страшно смотреть. Здание было модульным, я подготовил модули для стен, пола, потолка, дверей и окон. Очень быстро всё собиралось с функцией притягивания вертексов и можно было быстро выстроить нужное помещение. Всё было замечательно, пока при запекании света не вылезли все швы. То есть все модули отбрасывали тени на все модули и создавали ambient occlusion на своих гранях. Я потратил 5 дней на попытку всё исправить, но итог был тот же. Было решено просто отключить всё освещение для этого здания и помещения. Оно оказалось абсолютно плоским и мультяшным из-за этого, но времени больше не было.
Одним из важных моментов стало применение culling для камеры из скрипта для отдельных слоев. Настройки камеры позволяют выбрать только общую дальность обзора, что очень неудобно и не даёт нужного эффекта, а вот вызываемый из скрипта culling очень гибкий.
Последняя неделя и билд
В последнюю неделю разработки вышла новая версия Unity, точнее она уже была, но я решил почему-то обновится именно перед билдом до 2017.2.2f3. Пришлось обновить некоторые скрипты и разобраться с некоторыми особенностями Post Effects. Всё было хорошо, пока я не обнаружил ошибку во время билда — она была связана со стандартными шейдерами. Я долго рыскал на форумах и находил точно такие же сообщения, но без вменяемого решения. В итоге я принял решение откатиться до предыдущей версии, что снова заняло время и на исправление скриптов. Слава Богу, в предыдущей версии всё работало и билдилось.
Тестировал я всё в первый и последний раз перед выездом на конференцию, прямо ночью. Всё работало и было красиво, кроме того места со зданием, где пришлось убрать свет и тени, и соответственно объём. Я был доволен своей работой, и она, действительно, выглядела очень прилично, но после первого посетителя я узнал, много нового, в том числе, что мой вестибулярный аппарат намного крепче, чем я думал, и ещё много интересного об опыте пользователей и важности их участия в тестировании приложений для виртуальной реальности.
Заключение
Разработка игр явно стала доступнее даже не профессионалам, что само по себе очень интересный факт. Правда в некоторых моментах, при общении с профессиональными разработчиками, которые тоже презентовали похожие продукты на конференции, я стал задумываться о том, что нас отличает не так уж и много, но это лирика.
По делу, набор советов, чтобы насладиться разработкой и конечным результатом с наименьшим количеством нервов.
Перед разработкой
Коучеры Unity постоянно в своих презентациях повторяют, что сначала необходимо сделать игру интересной, а только потом уже работать над оптимизацией. Я не соглашусь с этим утверждением как минимум для VR, потому что 80% оптимизации лежит уже на этапе дизайна и за долго до работы с Unity. Если вы проигнорирует этот момент, то под конец разработки достигнуть необходимого framerate в 90 fps будет невозможно.
Сделайте скетчи всех сцен, в том числе с меню. Так как с VR Вам придётся использовать world-space canvas'ы и скорее всего не один, то их изначально продуманный дизайн так же сможет сэкономить доли или несколько ms времени на рендеринг
Продумайте заранее компоновку сцены и разделите её на несколько планов. В последствии Вы сможете «запечь» дальний план в свой skybox (возможно потребуется несколько повторов), сделать среднюю сцену статичной и применить один атлас текстур для неё, а все ближние объекты и активные элементы оптимизировать максимально соответствующими техниками.
Начальная сцена:
Сцена с активным дальним планом:
Сцена с активным ближним планом и фоном после 2-х процедур:
Моделирование
Если у Вас есть бюджет на модели, покупайте их. Разработка своих моделей имеет смысл только тогда, когда нужен абсолютно уникальный персонаж или объект. Большую часть повседневных вещей можно найти бесплатно с хорошей детализацией.
Обязательно создайте хотя бы одну версию модели с количеством полигонов в 10-15 раз меньше оригинальной. Она пригодиться на этапе разработки в Unity
Подгоняйте все модели под один масштаб так, чтобы при импорте/экспорте не менять коэффициентов масштаба в Unity, и тем более не менять значения Scale в классе Transform.
Экспортируйте все модели только с позицией (0,0,0) по абсолютным координатам, и передом выставленным по оси Z, если выставляете ось Y как вертикальную в настройках экспорта. Также перемещайте точку Pivot в самое выгодное место для использования. Особенно это касается объектов, к которым в последствии будут применены внешние силы и соединения.
Не забывайте сделать Reset Transform/Scale после работы над моделью, иначе конечное значение масштаба может вызвать неприятные последствия в Unity.
Создавайте 1 или 2 модели с уменьшенным количеством полигонов и центрируйте её с родительской. Экспортируйте родительскую и дочерние модели вместе, чтобы после добавления в Unity Вам не пришлось выставлять их в одну точку снова.
Проверяйте модель в Unity сразу после экспорта, чтобы позже не возвращаться к этапу моделирования.
Текстурирование
Для VR эффект от использования текстур типа Height минимален и не рекомендуется вообще для качественной оптимизации.
Используйте квадратные текстуры с разрешением кратным 128х128. Видеокарта будет обрабатывать такие данные быстрее, чем рандомные текструры разрешением типа 1070х981.
Атласы текстур Ваше всё. Количество используемых материалов должно сводиться к минимуму.
Unity
Все декорации должны быть помечены как статические объекты, а все объекты, которые будут менять своё положение по команде скриптов или физики, должны обязательно иметь компонент Rigidbody.
По возможности используйте skybox с текстурой вместо реальных объектов, если они располагаются достаточно далеко от пользователя.
Добавьте функцию обнуления (центрирования) положения игрока после запуска приложения. Как например, в игре Dead&Buried при нажатии и удержании обоих Thump Stick течении 3х секунд. В противном случае, любой шаг пользователя с надетыми очками может сместить его «виртуальную» голову с нужного места с вытекающими отсюда последствиями.
Количество вертексов в ПО для моделирования не отображает их реальное количество после импорта в Unity. Поэтому, если Вы планируется пользоваться такими функциями оптимизации, как Enable GPU Instancing для не статичных объектов, проверяйте это сразу после создания модели.
Oculus рекомендует не более 100 Draw Calls и не более 1000 Batch для необходимого быстродействия. В зависимости от ПК, которое Вы используете, Вы можете получить 90 кадров в секунду и с 400 Draw Calls и 3000 Batch, как в моём случае.
Я побывал разработчиком, можно сказать инди-девелопером, чему очень рад и это мне понравилось. Возможно, что этот опыт что-то изменит в моей жизни в будущем, потому что обычно так происходит: вещи, которые никогда бы не пришли в голову, меняют жизнь.
За кадром осталось много часов работы, которые не опишешь в одной статье, но я очень рассчитываю не быть ограниченным только этой публикацией.