Отдаём значения ориентации мобильного устройства камере

30 января 2016 12:33
Подскажите, как правильно преобразовать значения с датчика ориентации для передачи их камере. Ещё хотелось бы, что бы камера наклонялась по отношению к горизонту.

Попробовал использовать такую конструкцию:
function load_cb(data_id) {
    m_app.enable_controls();
    //m_app.enable_camera_controls();

    // place your code here
    var camobj = m_scs.get_active_camera();

    if (window.DeviceOrientationEvent) {
        window.addEventListener("deviceorientation", function(event) 
        {
            var xValue = event.gamma;
            var yValue = event.beta;
            var Rotation = event.alpha;
            
            //console.log({xValue:xValue,yValue:yValue,Rotation:Rotation});
            //console.log(m_trans.get_rotation(camobj));
            m_cam.rotate_camera(camobj, xValue/(-180/Math.PI), (yValue+90)/(90/Math.PI), true, true);
        }, true);
    }
}

Работает, но естественно не правильно
Не стой, где попало… Попадет еще раз.
http://naviris.ru/
30 января 2016 14:29
Есть несколько способов это сделать. Но я бы посоветовал использовать кватернионы. Однако, возможно, в API будет функция позволяющая уставнавлить поворот по трём углам.

А пока предлагаю следующее решение.
1) По углам alpha, beta, gamma построить кватернион поворота устройств (значение из датчиков).
2) Построить кватернион ориентации устройства (взять угол windows.orientation)
3) Умножить кватернион из 1) на кватернион из 2)
4) Взять кватернион поворота на угол Math.PI/2 вокруг оси OX (переход в мировую систему координат в движке)
5) Умножить кватернион из 3) на кватернион из 4)
6) Установить для объекта камеры кватернион поворота из пункта 5) (функция trans.set_rotation_v)
7) Установить вертикальную ось для камеры (функция camera.set_vertical_axis добавлена в версии 16.01 движка).
Например,
var up_axis = m_vec3.transformQuat(m_util.AXIS_Z,
result_quat, _vec3_tmp);
m_cam.set_vertical_axis(camobj, up_axis);

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

Скорее всего, данный функционал будет реализован в src/addons/gyroscope.js в рамках поддержки виртуальной реальности для мобильных устройств.
Команда Blend4Web
kirill@blend4web.com
30 января 2016 15:07
Кстати, забыл сказать, в движке имеется уже аддон gyroscope.js. Его функционирование можно понаблюдать в приложении viewer, активировав флаг на соответствующей панели (gyroscope).
Команда Blend4Web
kirill@blend4web.com
31 января 2016 11:12
Пока искал описание в документации, нашел баг в ней
https://www.blend4web.com/api_doc/module-controls.html#.create_gyroscope_angles_sensor
Вы можете использовать сенсоры для работы с гиродатчиком. Есть два сенсора: один возвращает угол наклона устройства, второй возвращает дельту, т.е. текущий угол минус предыдущий (название функции в документации, создающей этот сенсор указанно неверно)

Советую перед начало работы с гиродатчиками ознакомиться с вот этой статьёй. И посмотреть особенности работы самого гиродатчика.

Скорее всего, данный функционал будет реализован в src/addons/gyroscope.js в рамках поддержки виртуальной реальности для мобильных устройств.

Мы сейчас взялись за этот аддон, чтобы реализовать повороты камеры при движениях головы при использовании шлемов VR, работающих с мобильными девайсами. Возможно, что именно этот функционал вам и нужен (или частично нужен)
31 января 2016 15:57
Хорошо Проверил… В математических преобразованиях такого типа пока что не силён…
Не плохо было бы, что бы можно было обрабатывать данные через callback. Как в mouse.request_pointerlock шестым значением rotation_cb
Не стой, где попало… Попадет еще раз.
http://naviris.ru/
02 февраля 2016 16:14

В математических преобразованиях такого типа пока что не силён…
Написал пример, будет возможность проверьте пожалуйста.

//...
var m_cam = require("camera");
var m_ctl = require("controls");
var m_quat = require("quat");
var m_scenes = require("scenes");
var m_trans = require("transform");
var m_util = require("util");
var m_vec3  = require("vec3");

var _last_gyro_quat = m_quat.create();

var _quat_tmp = m_quat.create();
var _quat_tmp2 = m_quat.create();
var _vec3_tmp = m_vec3.create();
// ...
function create_rotation_sensors() {
    var obj = m_scenes.get_active_camera();
    var g_sensor = m_ctl.create_gyro_angles_sensor();
    var save_angles = true;

    var rotate_cb = function(obj, id, pulse) {
        if (pulse > 0) {

            var curr_angles = m_ctl.get_sensor_payload(obj, id, 0);
            if (m_cam.is_eye_camera(obj)) {
                var alpha = curr_angles[2];
                var beta  = curr_angles[1];
                var gamma = curr_angles[0];

                // 1) По углам alpha, beta, gamma построить кватернион поворота устройств (значение из датчиков).
                // http://w3c.github.io/deviceorientation/spec-source-orientation.html
                var quaternion = _quat_tmp;
                var c1 = Math.cos(alpha / 2);
                var c2 = Math.cos(beta  / 2);
                var c3 = Math.cos(gamma / 2);
                var s1 = Math.sin(alpha / 2);
                var s2 = Math.sin(beta  / 2);
                var s3 = Math.sin(gamma / 2);
                quaternion[0] = c1 * s2 * c3 - s1 * c2 * s3;
                quaternion[1] = c1 * c2 * s3 + s1 * s2 * c3;
                quaternion[2] = s1 * c2 * c3 + c1 * s2 * s3;
                quaternion[3] = c1 * c2 * c3 - s1 * s2 * s3;

                // 2) Построить кватернион ориентации устройства (взять угол windows.orientation)
                var orientation = Math.PI * window.orientation / 180;
                var screen_quat = m_quat.setAxisAngle(m_util.AXIS_Z,
                        -orientation, _quat_tmp2);

                // 3) Умножить кватернион из 1) на кватернион из 2)
                quaternion = m_quat.multiply(quaternion, screen_quat, _quat_tmp);

                // 4) Взять кватернион поворота на угол Math.PI/2 вокруг оси OX (переход в мировую систему координат в движке)
                var quat = m_quat.setAxisAngle(m_util.AXIS_X, Math.PI / 2,
                        _quat_tmp2);
                // 5) Умножить кватернион из 3) на кватернион из 4)
                quaternion = m_quat.multiply(quaternion, quat, _quat_tmp);

                // Дальше устанавливаем поведение, пусть будет работать гироскоп и touch
                if (save_angles) {
                    m_quat.copy(quaternion, _last_gyro_quat);
                    save_angles = false;
                } else {
                    var last_gyro_inv_quat = m_quat.invert(_last_gyro_quat, _last_gyro_quat);
                    var cam_quat = m_trans.get_rotation(obj, _quat_tmp2);
                    var clear_cam_quat = m_quat.multiply(cam_quat, last_gyro_inv_quat, _quat_tmp2);
                    var new_cam_quat = m_quat.multiply(clear_cam_quat, quaternion, _quat_tmp2);

                    var up_axis = m_vec3.transformQuat(m_util.AXIS_MZ,
                            new_cam_quat, _vec3_tmp);
                     // 7) Установить вертикальную ось для камеры (функция camera.set_vertical_axis добавлена в версии 16.01 движка).
                    m_cam.set_vertical_axis(obj, up_axis);
                    // 6) Установить для объекта камеры кватернион поворота
                    m_trans.set_rotation_v(obj, new_cam_quat);
                    m_quat.copy(quaternion, _last_gyro_quat);
                }
            }
        }
    }
    m_ctl.create_sensor_manifold(obj, "ROTATE_GYRO", 
            m_ctl.CT_CONTINUOUS, [g_sensor], null, rotate_cb);
}

};
Команда Blend4Web
kirill@blend4web.com
02 февраля 2016 20:56
Ответ на сообщение пользователя Кирилл Осипов
Написал пример, будет возможность проверьте пожалуйста.
Попробовал gyro_test (1).zip
Но что то у меня даже события датчика не воспроизводятся… (Версия SDK 16.01)

Добавил m_app.enable_controls() события появились, а вместе с ними и ошибка:
423
sfx.js:1151 Uncaught TypeError: Failed to execute 'setOrientation' on 'AudioListener': The provided float value is non-finite.

gyro_test (2).zip
Не стой, где попало… Попадет еще раз.
http://naviris.ru/
03 февраля 2016 11:08
а вместе с ними и ошибка
Проверил демку. На мобильных устройствах всё работает нормально. Если запускаете в десктопной версии браузера, то window.orientation не определено, поэтому все дальнейшие вычисления приводят к тому, что в set_vertical_axis подается вектор [NaN, NaN, NaN], это ломает некоторые параметры камеры. Поэтому, функцию create_rotation_sensors, описанную в демке, следует вызывать только для мобильных устройств.

Мы делаем базовые проверки входных параметров в API методах, т.к. проведение всех проверок было бы слишком ресурсозатратно для выполнения на JS.
Команда Blend4Web
kirill@blend4web.com
03 февраля 2016 15:14
Ответ на сообщение пользователя Кирилл Осипов
Проверил демку. На мобильных устройствах всё работает нормально.
Подтверждаю, протестил на xiaomi redmi note 2, отлично работает в стандартном браузере и в chrome.
Можно сделать проверку существования переменных/методов один раз при регистрации сенсора и выводить предупреждение в консоль .
А вообще большое спасибо за код, он делает то что нужно
Не стой, где попало… Попадет еще раз.
http://naviris.ru/
 
Пожалуйста, зарегистрируйтесь или войдите под своей учетной записью , чтобы оставлять сообщения.