понедельник, 2 июня 2014 г.

Unity3D for Windows Phone 8 - Gyro & Motion


В предыдущей статье я описывал работу компаса в Unity, для которого, чтобы получать нативные данные, был написан отдельный dll-плагин. На самом деле, в Unity компас работает также хорошо как и нативный, для этого нужно включить его Input.compass.enabled = true;. Но компас не всегда дает "хорошие", точные данные, потому что он подвержен воздействию внешних электромагнитных возмущений, из-за чего сильно сбивается, иногда даже при телефонных звонках. А чтобы его настроить нужно вращать телефон несколько раз, что совсем нереально когда он находится в закрытом, недоступном пространстве. Для решения особого круга задач связанных с вращением телефона, в условиях электромагнитных наводок, лучше использовать гироскоп.

GYROSCOPE
В API Windows Phone есть отдельный класс ответственный за работу с гироскопом Microsoft.Devices.Sensors.Gyroscope. Его я включил в сборную DLL для работы с "нативными" датчиками в Unity (почему объясню дальше).


В общем ничего необычного кроме специального метода - ToUnityVector3(). Этот метод преобразовывает вектор XNA в вектор Unity, при этом в него передается вызываемый объект через this в параметрах, это так называемый "методы расширения" (Extension Methods). Такое решение мне показал мой коллега из Interactive Lab, "евангелист Unity3D" Валентин Симонов.


Весьма элегантно. Но, лично я стараюсь избегать дополнительных преобразований и создания комплексных объектов (функционал которых излишен) в приложениях или играх работающих в реальном времени, т.е. у которых есть так называемый GameLoop (постоянные обновления с fps больше 30). Поэтому здесь реализованы дополнительные методы которые позволяют получить индивидуальные значения углов наклона устройства.

После долгих тестов выяснилось что гироскоп тоже расходится, основная ошибка накапливается при неравномерном вращении устройства в разные стороны. Также точность угла поворота по одной оси зависит от наклона устройства по другой, поэтому устройство должно быть как можно точнее выравнено по оси вращения.
Обработчик обновления гироскопа взят из стандартных примеров Windows Phone и выглядит следующим образом:


Данные гироскопа (e.SensorReading.RotationRate) представляют собой скорость смещение устройства по трем осям с момента последнего обновления (вызова функции обработчика). Чтобы получить реальные углы поворота, нужно скорость поделить на единицу времени dt, а затем прибавить полученные смещения к общему значению угла.
Прежде чем говорить о том как использовать это в Unity хочу сказать еще про один инструмент получения данных о положении (вращении) устройства.

Combined Motion
В документации MSDN этот инструмент описывается как :
"The Motion class handles the low-level sensor calculation and allows apps to easily obtain the device’s attitude (yaw, pitch, and roll), rotational acceleration, and linear acceleration both due to gravity and user movement. For typical apps that use this type of data, such as augmented reality apps, using the Motion class is recommended."
Motion API позволяет получать данные о наклоне устройства без каких либо дополнительных операций. Результаты получаются из сочетания данных с нескольких датчиков сразу: нормальные режим - использует компас и датчик ускорения, расширенный режим - это компас, акселерометр и гироскоп. Во втором режиме нужно проверять поддерживается ли гироскоп устройством. Работа с Motion API самая простая, получаемые данные чистые и не нуждаются в дополнительной обработке. Также, как заявляют в MSDN, если на устройстве есть гироскоп данные получаются более точные.


Здесь motionAttitudeReading это вектор с тремя углами поворота - Yaw, Pitch, Roll. На самом деле в MotionReading содержатся и другие данные о которых вы можете почитать тут.
В Unity этот Motion API выдается за простой гироскоп (для Windows Phone). Подключить его можно через Input.gyro.enabled = true;
Но при использовании этого инструмента у нас также возникают проблемы с наводками.

Unity Implementation - Панорама
Для получения нативных данных в Unity мною были разработаны несколько скриптов, которые вы можете использовать для своих целей, модифицировать и изменять как вам угодно (free and open source). Прежде всего это PanoramaCyclinder.cs компонент, который смотрит какие сенсоры-компоненты подключены к тому же "игровому объекту" (GameObject), получает и применяет с них данные через унифицированный интерфейс ISensorData. Выбор сенсора происходит по порядку - гироскоп, компас, motion.


Также есть возможность использовать Touch-перемещение для отладки анимации или других особенностей панорамы (галочка Use Touch).


Для всех сенсоров есть возможность выводить их данные в специальную консоль - GUIText или в методе OnGUI. Поскольку панорама использует только одну ось, то все "скрипты-датчики" ориентированы на вывод только одной оси - MainValue. 



При запуске (Start) каждый датчик проверяет получать нативные значения из плагина или получать Unity-значения. Параметр IsEnable определяет включен ли датчик как компонент на "гейм-объекте", таким образом можно тестировать-смотреть какие данные приходят от разных датчиков.

В Windows Phone нету стандартной функции постоянной работы экрана, т.е. когда телефон не переходит в ждущий режим. Это можно сделать только самостоятельно через вывоз специальных методов API устройства.


В результате мы получили: с гироскопом тоже есть проблемы - он расходится со временем и даже едет. Поэтому для решения панорамы нужно использовать дополнительный "физический" датчик, к примеру на arduino или какие либо метки и алгоритм для корректировки значения.


Все скрипты можно найти на github

Комментариев нет:

Отправить комментарий