Статьи

Дополненная реальность в браузере с Awe.js

Дополненная реальность — изящная концепция. Мы рассматриваем окружающий мир и дополняем его изображениями, текстом, звуком и видео. Технологические компании начинают изучать возможности AR с такими устройствами, как Meta Glasses , Microsoft HoloLens и Magic Leap . Эти очень интересные AR-гарнитуры еще не совсем готовы к выпуску для потребителей, поэтому может пройти некоторое время, прежде чем в каждом доме появится пара. Однако есть еще один способ познакомить мир с дополненной реальностью, используя что-то, к чему у них может быть более легкий доступ — мобильный браузер.

Ранее я освещал другие виды создания и манипулирования реальностью с использованием JavaScript и Three.js здесь, в SitePoint, в своих статьях о том, как перенести виртуальную реальность в Интернет с помощью Google Cardboard и Three.js и о фильтрации реальности с помощью JavaScript и Google Cardboard . В этой статье я покажу, как вы можете использовать библиотеку JavaScript под названием awe.js для создания дополненной реальности в мобильном Интернете. Мы собираемся создать 3D панель управления, которая открывается поверх бумажного маркера. Мы можем подключить его, чтобы сделать практически все, что можно включить с помощью HTTP-запроса JavaScript, поэтому я настроил его на изменение цвета моей лампочки LIFX с помощью IFTTT.

Что вам нужно

Для этой демонстрации вам потребуется Google Chrome для мобильных устройств. Он может потенциально работать и в Firefox для мобильных устройств, однако я обнаружил, что при нажатии на HTC One M9 события щелчка для меня не сработали. Он также работает в некоторых браузерах для настольных компьютеров (Chrome и Opera работали довольно хорошо на моем Mac), но определенно не совсем то же, что смартфон с сенсорными событиями. Это может быть аккуратно на планшете, хотя.

Вам также понадобится учетная запись IFTTT и знание того, как настроить канал Maker с правилами, которые запускаются по HTTP-запросам. Если вы новичок в IFTTT, ранее мы рассмотрели основы в статье « Подключение лампочек LIFX к IoT с помощью IFTTT» . Для новичков в канале Maker мы также рассмотрели это в разделе «Подключение IoT и Node.js к IFTTT» .

Наконец, вам нужно распечатать маркер на листе бумаги. Маркер, который мы будем использовать:

Маркер № 64

Код

Если вы предпочитаете прямо войти в код и попробовать его, все это доступно на GitHub .

Awe.js

Awe.js — это библиотека JavaScript, которая использует Three.js, камеру вашего устройства и некоторые довольно умные методы для создания дополненной реальности в браузере. Вы можете скачать библиотеку и некоторые образцы в репозитории awe.js GitHub . Он предоставляет четыре вида AR, каждый со своим собственным примером в репо:

  • geo_ar
  • grift_ar
  • leap_ar
  • marker_ar Это тот, с которым мы будем работать в этой демонстрации.

Наш демо-код дополненной реальности

Наш демонстрационный код содержит более 300 строк, но во многом это повторяющийся код для похожих объектов. Я бы порекомендовал загрузить демонстрационный код из репозитория GitHub демо и следовать инструкциям, приведенным здесь. Как только вы поймете, как все это работает, попробуйте поиграть и создать что-то свое.

Все начинается с события loadwindow Самое первое, что мы включаем, — это переменная, которая отслеживает, открыта ли наша панель управления AR (для краткости я назвал ее «меню») или нет. Изначально он закрыт.

 window.addEventListener('load', function() {
    var menu_open = false;
    
    // Our code continues here
  });

Затем мы начинаем использовать библиотеку awe.js. Все, что мы делаем, определяется внутри функции window.awe.init() Мы начнем с некоторых глобальных настроек для нашей AR-сцены.

 window.awe.init({
    device_type: awe.AUTO_DETECT_DEVICE_TYPE,
    settings: {
      container_id: 'container',
      fps: 30,
      default_camera_position: { x:0, y:0, z:0 },
      default_lights: [{
        id: 'point_light',
        type: 'point',
        color: 0xFFFFFF
      }]
    },
  • device_typeawe.AUTO_DETECT_DEVICE_TYPE До сих пор я не видел необходимости менять это.
  • settings Это включает:
    • container_id
    • fps
    • default_camera_position
    • default_lights Наше демо имеет только один белый Three.js PointLight. Для типа источника света доступен ряд опций, соответствующих различным типам источников света Three.js'area''directional''hemisphere''point''spot'

Как только наши настройки будут выполнены, мы определим, что делать после инициализации awe.js. Все обернуто в функцию awe.util.require() Будьте внимательны, чтобы определить только те возможности браузера, которые вам нужны для демонстрации, так как вы можете излишне запретить вашему приложению AR работать в некоторых браузерах, если вы определите их неправильно, используя возможности, перечисленные в некоторых других их примерах GitHub. Например, чтобы расположить элементы на основе точек компаса, вам необходим доступ к функции 'gyro' Это не будет работать на большинстве настольных браузеров. Нам не нужно это в этой демонстрации, поэтому мы исключаем это.

 ready: function() {
    awe.util.require([
      {
        capabilities: ['gum','webgl'],

Определенные файлы используют определенные функции для awe.js — lib/awe-standard-dependencies.jslib/awe-standard.jslib/awe-standard-window_resized.js Наше демо использует маркеры, для чего требуются два других файла, перечисленных ниже.

 files: [ 
    ['lib/awe-standard-dependencies.js', 'lib/awe-standard.js'],
    'lib/awe-standard-window_resized.js',
    'lib/awe-standard-object_clicked.js',
    'lib/awe-jsartoolkit-dependencies.js',
    'lib/awe.marker_ar.js'
  ],

После того, как все эти файлы были успешно загружены, мы запускаем функцию awe.js с удачным названием success() Первая функция, которую вы всегда будете запускать, когда будете готовы начать показ элементов, настраивает сцену awe.js.

 success: function() {
    window.awe.setup_scene();

Все элементы в awe.js расположены в «точках интереса» (POI). Это конкретные точки в сцене, отмеченные с помощью координат, внутри которых могут быть расположены объекты. Вы можете перемещать POI внутри awe.js, а также сами элементы. Мы создаем один POI, который будет размещен везде, где виден определенный бумажный маркер. Для создания POI мы используем функцию awe.pois.add()

Я дал ему идентификатор 'marker' Мы устанавливаем его начальную позицию равной (0,0,10000), которая немного позиционирует его, пока мы не будем готовы его использовать. Мы также устанавливаем его невидимым до тех пор, пока не обнаружим маркер.

 awe.pois.add({id: 'marker', position: {x: 0, y: 0, z: 10000}, visible: false});

Элементы, которые мы добавляем в наши POI, называются «проекциями» в awe.js. Первую проекцию, которую мы добавили в нашу сцену, я назвал 'wormhole' Точно так же, как и идентификатор POI, вы можете назвать свое имя абсолютно любым, при условии, что оно соответствует другим ссылкам на него в вашем коде. Мы добавляем его в нашу POI, используя функцию awe.projections.add()

 awe.projections.add({ 
    id: 'wormhole',
    geometry: {shape: 'plane', height: 400, width: 400},
    position: {x: 0, y: 0, z: 0},
    rotation: {x: 90, z: 45},
    material: {
      type: 'phong',
      color: 0x000000
    }
  }, {poi_id: 'marker'});

Существует довольно много вариантов объектов, которые мы можем добавить в качестве проекций, поэтому я объясню их более подробно. Обратите внимание — все значения x, y и z здесь для позиционирования и поворота связаны с его POI. Этот POI определяется в самом конце своим идентификатором как {poi_id: 'marker'}

  • geometry Параметры, необходимые для каждого типа геометрии, соответствуют параметрам, указанным в файле awe.js. Например, SphereGeometry в Three.js будет представлен как {shape: 'sphere', radius: 10} Для тех, кто использует последний Three.js, в текущей доступной версии awe.js BoxGeometry все еще использует CubeGeometry. Итак, для создания блоков мы используем формат {shape: 'cube', x: 20, y: 30, z: 5}
  • position
  • rotation Я поворачиваю червоточину на 90 градусов вокруг оси x, чтобы она лежала ровно на столе, и под углом 45 градусов относительно оси z, как мне показалось, что это выглядело более естественным (оно не всегда точно совпадает с маркером, поэтому это по диагонали делает это менее очевидным).
  • material Я придерживался 'phong'MeshPhongMaterial'lambert''shader''sprite''sprite_canvas' Мы также можем определить его цвет в шестнадцатеричном виде.
  • texture Чтобы определить текстуру, вы можете включить texture: {path: 'yourtexturefilename.png'}

В демоверсии я добавляю к сцене семь различных блоков / кубов, каждый из которых имеет высоту 30 пикселей и размещается на 31 пиксель ниже по оси y, чтобы он был изначально скрыт червоточиной. Они все немного разной ширины, чтобы они выглядели как лампочка.

Я перемещаю их немного назад от центра червоточины через их координаты x и z, но, если честно, было бы неплохо остаться с 0 и для тех, кто, если -5 ошибается. Я повернул его на 45 градусов по оси Y, чтобы он смотрел под большим углом на вершине червоточины.

 awe.projections.add({
    id: 'ar_button_one',
    geometry: {shape: 'cube', x: 60, y: 30, z: 5},
    rotation: {y: 45},
    position: {x: -5, y: -31, z: -5},
    material: {
      type: 'phong',
      color: 0xFF0000
    }
  }, {poi_id: 'marker'});

Каждый из них имеет идентификатор 'ar_button_{NUMBER}' Мы будем использовать этот идентификатор в наших HTTP-вызовах IFTTT, поэтому важно сохранять их согласованность и точность!

После определения наших проекций мы определяем довольно важную часть нашей головоломки AR — событие обнаружения маркера. Мы добавляем это как массив, переданный в функцию awe.events.add()

 awe.events.add([
    // Our events here
  ]);

У нас только одно событие awe.js, поэтому здесь есть только одно событие. Событие определяется с помощью идентификатора, который мы могли бы назвать чем угодно. Я назвал это 'ar_tracking_marker' Мы определяем типы устройств, к которым он применим. Похоже, что это одинаково во всех примерах awe.js в их репозитории, поэтому я оставил его как есть, для ПК и Android установлено значение 1.

 id: 'ar_tracking_marker',
  device_types: {
    pc: 1,
    android: 1
  },

Затем у нас есть функции register()unregister()

 register: function(handler) {
    window.addEventListener('ar_tracking_marker', handler, false);
  },
  unregister: function(handler) {
    window.removeEventListener('ar_tracking_marker', handler, false);
  },

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

 handler: function(event) {
    if (event.detail) {
      if (event.detail['64']) {
        // Our response!
      }

В рамках нашего ответа на поиск маркера мы хотим переместить наш POI, который мы назвали 'marker' Мы преобразуем его, чтобы выровнять по физическому маркеру, используя event.detail['64'].transform

 awe.pois.update({
    data: {
      visible: true,
      position: {x: 0, y: 0, z: 0},
      matrix: event.detail['64'].transform
    },
    where: {
      id: 'marker'
    }
  });

Мы также установили, чтобы наша проекция 'wormhole'

 awe.projections.update({
    data: {
      visible: true
    },
    where: {
      id: 'wormhole'
    }
  });

Если мы не видим маркер, но наше меню открыто, мы оставим его открытым, но спрячем червоточину. Основная причина этого заключается в том, что при некоторых изменениях света маркер может стать неразборчивым. Мы не хотим поймать себя в определенный цвет света без возможности повернуть назад!

 else if (menu_open) {
    awe.projections.update({
      data: {
        visible: false
      },
      where: {
        id: 'wormhole'
      }
    });
  }

Если маркера нет, а наше меню не открыто, то весь POI скрыт, и мы ожидаем его просмотра.

 else {
    awe.pois.update({
      data: {
        visible: false
      },
      where: {
        id: 'marker'
      }
    });
  }

Мы заканчиваем, говоря awe.js, чтобы обновить сцену.

 awe.scene_needs_rendering = 1;

Последняя часть реальной функциональности, которую мы будем настраивать, это наши события нажатия. Все они находятся в событии object_clicked

 window.addEventListener('object_clicked', function(e) {
    // Our click events
  });

Наше событие click содержит идентификатор проекции, которая была нажата в e.detail.projection_id Мы используем оператор switch, чтобы определить, как реагировать на щелчок. Щелчки на червоточине открывают и закрывают виртуальное меню, в то время как щелчки на кнопках виртуального меню активируют наши светлые цвета. Мы используем оператор switch, поскольку каждая из кнопок запускает один и тот же код ответа.

 switch (e.detail.projection_id) {
    case 'wormhole':
      // Clicks to open and close our menu
    break;
    case 'ar_button_one':
    case 'ar_button_two':
    case 'ar_button_three':
    case 'ar_button_four':
    case 'ar_button_five':
    case 'ar_button_six':
    case 'ar_button_seven':
      // Clicks on our virtual menu buttons
    break;
  }

Наши события щелчка червоточины открывают и закрывают меню в зависимости от того, является ли menu_open Если значение равно false, то мы используем функцию awe.js awe.projections.update() Это выводит его из червоточины. Единственная разница между перемещением каждой проекции состоит в том, насколько каждый объект перемещается по оси Y.

 if (!menu_open) {
    awe.projections.update({
      data: {
        animation: {
          duration: 1
        },
        position: {y: 35}
      },
      where: {id: 'ar_button_one'}
    });

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

 else {
    awe.projections.update({
      data: {
        animation: {
          duration: 1
        },
        position: {y: -31}
      },
      where: {id: 'ar_button_one'}
    });

После нашего оператора if else мы переключаем menu_open

 menu_open = !menu_open;

В рамках нашего события нажатия кнопки мы делаем HTTP-запрос к IFTTT, который включает идентификатор нашей кнопки в качестве имени события и наш ключ для доступа к услуге IFTTT. На самом деле мы не используем возвращаемые данные, мы записываем их на консоль для целей отладки, но в противном случае фактические результаты поступают от IFTTT, реагирующего на вызов HTTP.

 ...
  case 'ar_button_seven':
    var request = new XMLHttpRequest();
    request.open('GET', 'http://maker.ifttt.com/trigger/'+e.detail.projection_id+'/with/key/yourkeyshouldbehere', true);

    request.onload = function() {
      if (request.status >= 200 && request.status < 400) {
        var data = JSON.parse(request.responseText);
        console.log(data);
      }
    };

    request.send();
  break;

После всего этого, если awe.js не загружается из-за несовместимости и т. Д., У нас есть альтернативный скрипт, который загружается, чтобы показать сообщение об ошибке.

 {
    capabilities: [],
    success: function() { 
      document.body.innerHTML = '<p>Try this demo in the latest version of Chrome or Firefox on a PC or Android device</p>';
    }
  }

Время HTTPS

Обновление от конца 2015 года — я возвращаюсь к этой статье, чтобы добавить новую довольно важную информацию — Chrome теперь требует, чтобы веб-страницы, использующие камеру, обслуживались по HTTPS. Поэтому, прежде чем пытаться выполнить это, вам нужно найти способ запустить свой сервис через HTTPS. Один из методов, которые я использовал для тестирования, — это ngrok, который может предоставить HTTPS-туннель вашему локальному хосту. У нас есть руководство по доступу к Localhost From Anywhere здесь, на SitePoint, которое поможет вам начать работу.

Демо в действии

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

Наша AR червоточина появляется

Если мы нажмем на червоточину, наши кнопки меню должны оживить свои места.

Наша червоточина открылась и видна

Если мы нажмем один из пунктов меню …

Выбор красного в нашем меню AR

Это должно изменить цвет нашего LIFX света!

Наши огни меняются на красный

Вывод

Это все, что вам нужно знать, чтобы начать работу с дополненной реальностью в браузере с помощью awe.js. Он имеет большой потенциал, как и многие разработки в мире технологий в наши дни! Команда awe.js постоянно работает над плагином, и скоро должна появиться более новая и еще более полнофункциональная версия! Можно также настроить стереоскопический эффект three.js для использования в Google Cardboard и объединить его с некоторыми функциями awe.js для создания опыта работы с гарнитурой AR. Я думал, что это может быть немного для одной статьи, так что следите за будущей статьей на эту!

Если вы экспериментируете с магией AR, используя этот код, или продолжите, оставьте записку в комментариях или свяжитесь со мной в Твиттере ( @thatpatrickguy ), я хотел бы проверить это!