Виртуальная реальность на Windows Phone с помощью Unity3d
На последней Game Developer Conference было много новостей связанных с виртуальной реальностью. Это и новые устройства, такие как Microsoft HoloLens, борьба за признание между Oculus Rift и Project Morfeus, анонс SteamVR. Все это говорит о том, что тема очень интересная и горячая. Хотя понятие виртуальной реальности включает в себя очень много всего, технологически это в первую очередь очки или шлем которые показывают стереоскопическое изображение и реагируют на движение. Многие из нас хотели бы поэкспериментировать в этой области, но без устройства, например, Oculus Rift это затруднительно. К счастью существуют технологии, которые могут превратить ваш телефон Windows Phone в шлем виртуальной реальности.
С чего начать
Самое главное это конечно шлем, или если угодно очки. Их надо изготовить так чтобы они позволяли держать телефон перед глазами. Можно воспользоваться Google Cardboard или изготовить их самостоятельно из картона, акрила и пластика.
После того как вы изготовите очки, или шлем, в общем то, что будет держать у вас телефон перед глазами, возникает вопрос что же необходимо сделать чтобы погрузиться в ту самую виртуальную реальность:
- Создать стереоскопическую картинку
- Менять ее в зависимости от положения головы
- Взаимодействовать с виртуальным миром
Создаем проект Unity3d
Создайте пустой Unity3d проект и создайте по вкусу какие-либо 3D объекты, добавьте освещение. С другой стороны, можно воспользоваться готовым бесплатным Medieval Home пакетом, импортируйте его и откройте сцену пример (Scene/Sample Scene).
Далее следует сконфигурировать экспорт проекта. Для этого зайдите в меню Edit / Project Settings / Player и выберите иконку Windows Store.
Самый главный пункт это кнопка «TestCertificate». Нажмите на кнопку Create и создайте новый. К сожалению, в Unity присутствует небольшой баг, связанный с тем что диалог Create в некоторых случаях не работает. Чтобы обойти эту проблему, запустите Visual Studio 2013, создайте новый проект Windows Phone 8.1, откройте папку в которой находится этот проект и найдите файл *.PFX. Переименуйте его в WSATestCertificate.pfx и скопируйте в папку Assets текущего проекта Unity.
Далее следует сконфигурировать билд. Зайдите в меню File / Build Settings и выберите следующие значения для Windows Store:
Не забудьте предварительно сохранить текущую сцену (File / Save Scene) и нажать кнопку «Add Current» в этом диалоговом окне, чтобы в результирующем проекте появилась стартовая сцена. После нажатия на кнопку Build будет создан проект Visual Studio 2013 который для проверки следует открыть в Visual Studio, скомпилировать и запустить на устройстве.
Создаем стереоскопическую картинку
Первое что необходимо сделать в проекте – создать стереоскопическое изображение. И это очень легко сделать так как у нас есть трехмерная сцена, которую можно просчитать для каждого глаза.
Найдите в проекте First Person Controller и продублируйте основную камеру (правая кнопка мыши, Duplicate).
У вас должно получиться следующее:
Далее в свойствах для каждой камеры необходимо указать что рендер изображения ведется только на половину так называемого въюпорта (viewport). Для левого и правого глаза соответственно в начале экрана, и в его второй половине:
Но на этом конечно не все, стерео-изображение так не получить, картинки которые сейчас отображаются этими камерами, одинаковы.
Для того чтобы появился стерео-эффект, необходимо ввести параллакс между этими камерами.
Добавим в проект новый C# скрипт:
Назовите его FPSVRBehavior.cs и после того как он будет создан, перетащите его мышью на «First Person Controller». Созданный скрипт будет подключен к этому обьекту.
Теперь можно приступить к задаче создания параллакса между камерами. В методе Start() класса FPSVRBehavior просто зададим смещение «левого глаза» от основного объекта «родителя» на небольшую величину:
var leftEye = GameObject.Find("LeftEye");
leftEye.transform.Translate(Vector3.left * 0.1f);
Стереоизображение готово, создайте новый билд, опубликуйте его на телефон и насладитесь стереоизображением в ваших виртуальных очках! Правда изображение это статичное, а в настоящих шлемах отслеживается положение головы и в зависимости от него меняется изображение на экране.
Учитываем положение головы
В телефонах Windows Phone есть датчик гироскопа. Его можно использовать для наших целей. Осталось только научиться использовать данные которые возвращает этот датчик.
Некоторое отступление от основной темы, пишем плагин для Unity
Как известно, Unity3d это кроссплатформенный инструмент создания приложений. При всей его универсальности, некоторые узкие моменты и специфичные для устройств API недоступны. Для того чтобы нам добраться до значений данных датчика гироскопа, придется подготовить плагин. Не вдаваясь в детали, плагин это два DLL с одинаковым именем которые размещаются в каталоге Assets/Plugins и Assets/Plugins/Metro.
Файл WindowsPhoneVRController.dll который находится в каталоге /Assets/Plugins это стандартная сборка .NET Framework 3.5 которая предназначена для работы во время дизайнера Unity.
Аналогичный файл который находится в каталоге /Assets/Plugins/Metro это Windows Store 8.1 Class Library, и он используется средой Unity для создания Visual Studio solution, чтобы наш проект на целевой платформе получил нужные функции. Более подробно о том как создавать плагины можно почитать в моем блоге.
Исходный код для обеих DLL одинаков:
#if NETFX_CORE
using System.Threading.Tasks;
using Windows.Devices.Sensors;
#endif
namespace WindowsPhoneVRController
{
public class Controller
{
#if NETFX_CORE
Gyrometer gyro;
#endif
public Controller()
{
#if NETFX_CORE
gyro=Gyrometer.GetDefault();
#endif
}
public static void Vibrate()
{
Vibrate(8);
}
public double AngularVelocityX
{
get
{
#if NETFX_CORE
return gyro.GetCurrentReading().AngularVelocityX;
#else
return 0;
#endif
}
}
public double AngularVelocityY
{
get
{
#if NETFX_CORE
return gyro.GetCurrentReading().AngularVelocityY;
#else
return 0;
#endif
}
}
public double AngularVelocityZ
{
get
{
#if NETFX_CORE
return gyro.GetCurrentReading().AngularVelocityZ;
#else
return 0;
#endif
}
}
public static void Vibrate(int _milliseconds)
{
#if NETFX_CORE
var vibrationDevice = Windows.Phone.Devices.Notification.VibrationDevice.GetDefault();
vibrationDevice.Vibrate(TimeSpan.FromMilliseconds(_milliseconds));
#endif
}
}
}
В зависимости от #CONDITION при компиляции для .NET Framework 3.5 получаем «заглушку», а при компиляции для Windows Store – рабочую логику. В готовом примере, ссылка на который находится внизу, подготовлен Visual Studio solution который компилирует оба DLL и раскладывает их по соответствующим каталогам Assets/Plugins
Учитываем значения датчика
Как уже становится понятно из исходного кода, работа с датчиком гироскопа очень проста. Опрашиваем значения ускорений вращения телефона и далее останется только повлиять на изображение на экране с помощью этих данных.
Для этого опять откроем файл FPSVRBehavior.cs и в методе Update добавим следующий код:
void Update ()
{
float vertical_angle_delta = (float)gyroscopePlugin.AngularVelocityY * 0.05f;
float horisontal_angle_delta = (float)gyroscopePlugin.AngularVelocityX * 0.05f;
transform.localEulerAngles = new
Vector3(transform.localEulerAngles.x+vertical_angle_delta ,
transform.localEulerAngles.y-horisontal_angle_delta,
transform.localEulerAngles.z);
}
gyroscopePlugin это экземпляр нашего плагина, не забудьте объявить переменную в этом классе и создать этот объект в методе Start();
Как стало понятно из кода, просто опрашиваем данные датчиков, и меняем положение объекта — в нашем случае это First Person Controller. Магический коэффициент 0.05f влияет на то, с какой скоростью будет реагировать изображение на вращения телефона.
После того как вы соберете билд и запустите приложение на телефоне, камера оживет и теперь будет отслеживать положение головы!
Движение это жизнь
Теперь у нас есть практически полноценное приложение виртуальной реальности, но в этой виртуальной реальности пока можно только вращать головой. Для того чтобы двигаться вперед, необходимо предусмотреть какой-то механизм. Дотрагиваться до экрана нет возможности (телефон у нас перед глазами), подключать дополнительные устройства к телефону затруднительно, да и не удобно. Поэтому предусмотрим элегантный и простой способ, как нам ходить внутри нашего виртуального мира.
Способ этот очень прост – если наклонить немного голову (телефон), так чтобы виртуальная камера смотрела в пол, на определенном угле First Person Controller двигается вперед. Естественно, с учетом коллизий в нашем виртуальном мире, чтобы не проходить сквозь стены.
Добавим следующий код в метод Update класса FPSVRBehavior:
var motor = GetComponent<CharacterMotor>();
if (transform.localEulerAngles.x > 30 && transform.localEulerAngles.x < 40)
{
motor.inputMoveDirection = transform.rotation*(Vector3.forward * 0.1f);
WindowsPhoneVRController.Controller.Vibrate();
}
Код самоочевиден – если наклоняем голову, то где-то между 30 и 40% градусами есть зона, которая приводит к движению вперед. Чтобы «ощущать» где эта зона, помогаем пользователю вибрацией телефона.
Загружайте готовый проект и погружайтесь в виртуальную реальность!