Виртуальная реальность в 2D

Рассказывает Питер ван дер Зей, автор блога qfox.nl


Я, как и многие в последнее время, подхватил идею виртуальной реальности. Нет, серьезно. За ней будущее. И мое в том числе. И это будущее будет очень большим. В этой статье я расскажу об эксперименте, который проделал недавно. Недавно я улучшал свою демку метода «бросания лучей» так, чтобы она работала с Google Cardboard (дешевый способ испытать виртуальную реальность на своем опыте, имея под рукой только картонную коробку и смартфон).

Если вы не хотите ничего читать, то вот здесь лежит сам результат моего эксперимента. Кроме самой демонстрации метода «бросания лучей», там есть еще несколько интересных опций, с которыми можно поиграть.

Если честно, то я не думаю, что в ближайшем времени у меня получится сделать так, чтобы все рендерилось с частотой 90 или 60 кадров в секунду. Кроме того, мобильные браузеры накладывают ограничение в 30 кадров в секунду, но даже на современных флагманах (например, Galaxy Note 4) максимум, что мне удавалось выжать — 20 кадров в секунду. Конечно, этого достаточно для тестирования и беглого знакомства с виртуальной реальностью, но, очевидно, ничего серьезного сделать не получится, даже если это будет просто казуальный гейминг.

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

Двойной рендеринг

Каждый кадр рендерится дважды с едва видимым изменением положения объектов и угла их видения. Все это можно настроить на лету. Открыто скажу, что данное демо не предназначено для тестирования некоторых определенных параметров. Для получения наилучшего результата желательно смотреть в одном направлении.

Камерам выделен отдельный «холст». На нем сначала отображается все окружение. Статичные объекты: миникарта, меню, информация для дебага, различные сообщения — генерируются один раз, а затем все время отрисовываются в одном и том же месте. Это дает прирост в производительности.

API геймпада

Демка поддерживает управление геймпадом, правда, работает оно пока довольно плохо. Я тестировал его только с Samsung GearVR joypad на Samsung Galaxy Note 4, и я практически уверен, что на других устройствах некоторые функции работать не будут. Кроме того, я абсолютно не имею представления, как управление будет работать на других операционных системах, на iOS, например.

Для меня это был первый раз, когда я работал с геймпадным API, но без этого нельзя было обойтись. Походить и оглядеться вокруг можно и с помощью геймпада, но для выполнения более сложных действий нужно дополнительное устройство ввода.

В своем эксперименте я обрабатывал ввод с геймпада и клавиатуры, и в целом все работает довольно прилично, но, как было сказано ранее, ввод с геймпада требует доработки. В конце концов, синглтон Input объединит в себе другие, более мелкие синглтоны для различных устройств. Демо-версия, как ей и положено, лишь показывает общие принципы, которые затем превратятся в нечто большее.

Управление

С помощью стрелок можно управлять движением. Аналоговые стики отвечают за регулировку «носа» — точки фокуса, куда вы направляете свой взгляд, когда смотрите прямо. Правый изменяет угол камеры, левый — дистанцию «носа».

Select перезагрузит страницу (очень удобно при разработке). Start откроет меню. Кнопки R и L позволяют переключаться между разными опциями в меню.

Четыре кнопки — «ABXY» (или «1234»): «А», которая находится ниже всех, открывает меню отладки, в котором можно увидеть, какие клавиши геймпада обнаружены и функционируют. Если же эта панель не горит зеленым, то не был обнаружен сам джойстик.

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

«Х» (левая) переключает наборы текстур. Всего есть три текстуры, на каждой может быть написано слово «cat» с целью облегчения ориентирования. Также есть текстуры, взятые из игры Wolfenstein или окрашенные в случайные цвет.

«Y» включает миникарту. Все просто.

В меню находятся пять опций. Пока оно открыто, вы не можете двигаться.

FOV просто меняет угол обзора. Еще можно скорректировать оптическое искажение под себя, если ваш браузер поддерживает WebGL.

«Cover» отображает зеленый круг над «холстом», стрелками можно выбрать его размер, а также будет ли показываться он вообще. Проведите интересный опыт — включите круг и увеличивайте его размер до тех пор, пока все не станет зеленым. Затем выньте смартфон из картонки и посмотрите, какую часть экрана вы видите на самом деле.

«Grid» позволяет отображать сетку в шести разных режимах: rectangle-distorted, rectangle-straight, rectangle-mixed, circle-distorted, circle-straight и circle-mixed. Кроме того, можно изменять размер сетки. Проще говоря, можно отрисовывать квадратную или круговую сетку и выбирать, применяется ли к ней искажение или нет. Ради интереса можете выключить искажение на одной камере и оценить разницу. Еще можно изменять способ прорисовки лучей: прямоугольный или трапециевидный. Трапециевидный дает лучшую картинку, но он намного медленнее прямоугольного, так как рисует по одной вертикальной пиксельной полоске вместо целого луча сразу. Способа делать это по-другому на 2D-холсте пока нет.

В «HMD» можно выбрать два типа настроек: «деревянный» и «полный» — они отвечают за размер камер. «Деревянный» делался для моей картонки, при нем камеры занимают только часть экрана. При «полном» камеры занимают весь экран, однако это ведет к уменьшению FPS. Для устройств с большим экраном по умолчанию выбран «деревянный».

«View» позволяет настраивать камеры. Стрелками влево-вправо можно менять их ширину, вверх-вниз — высоту (я знаю, что при настраивании ширины левый «холст» подлагивает, но у меня не было времени разобраться с этой проблемой). Движением влево-вправо правого аналогового стика изменяется величина искажения (идеальное значение для меня — 0.035), а вверх-вниз — расстояние между камерами. Левым аналоговым стиком можно передвигать камеры по экрану.

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

Всем клавишам на джойстике соответстуют клавиши на клавиатуре, смотрите страницу демки для справки.

Искажение

Так как вы смотрите на экран через выпуклые линзы, необходимо корректировать изображение. Такая корректировка называется бочкообразным искажением. Это видео подробно рассказывает про него.

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

Искажение автоматически отключается, если не может получить доступ к WebGL. Вы можете включить его, нажав стрелку вверх в меню при выбранной опции «FOV».

Да и мне самому не нравится моя реализация. Искажение слишком сильное в центре и слишком слабое по бокам. Хотелось бы знать, как это исправить.

Трудно сказать, какой коэффицент лучше всего. Пока что мне больше всего нравится 1.035. Хотелось бы сделать его чуть выше, однако при этом центр искажается слишком сильно. Но что еще хуже — отключение этого эффекта почти никак не влияет на изображение. Нужно будет покопаться в этой проблеме поглубже.

Метод «бросания лучей»

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

Послесловие

Что еще? Не знаю. Как я уже сказал, демо вы можете найти здесь. Вскоре я добавлю его на страницу со своими проектами. Все равно я не обновлял ее уже два года :р

Работать над этим экспериментом было весело. Я занялся математикой, узнал, что нужно и что не нужно делать при работе с виртуальной реальностью, и открыл ящик Пандоры, наполненный моими вопросами касательно этой темы. Сейчас я хочу отодвинуть эту демку на задний план и работать над чем-то более серьезным — например, WebGL. А может быть, вообще отойду от веб-разработки.

Сейчас я понял, что если хочу делать что-то серьезное в этой области, то, скорее всего, придется отказаться от браузеров. Их разработчики просто не прилагают достаточно усилий в этом направлении. Насколько я знаю, на время написания этой статьи пара людей из Google и Mozilla работают над WebVR. Я ценю их старания, но, очевидно, два человека многого сделать не могут. Кроме того, в WebVR важно железо. Оно должно быть как в Oculus Rift, а не как в смартфоне, засунутом в картонку.

Тем не менее, я считаю, что подход с картонкой имеет право на жизнь. Достаточно просто купить специальный кейс за 10$, и вы можете испытать виртуальную реальность на себе, не тратя сотни долларов. Конечно, впечатление будет не таким сильным, как при использовании Oculus и GearVR, но все же…

Думаю, вскоре я займусь написанием простенькой демонстрации возможностей WebGL. Посмотрим, смогу ли я довести ее до удовлетворительного уровня в плане производительности.

Перевод статьи «VR in 2d canvas»