Виртуальная реальность приходит в Интернет

Несколько основ, которые подготовят вас к широкому спектру захватывающих впечатлений: виртуальная реальность, дополненная реальность и все, что между ними.

Джо Медли
Joe Medley

В Chrome 79 появились возможности погружения в Интернет. API устройств WebXR обеспечивает виртуальную реальность, а в Chrome 81 появилась поддержка дополненной реальности. А обновление API GamePad расширяет возможности расширенного использования элементов управления на VR. В ближайшее время эти спецификации будут поддерживать и другие браузеры, в том числе Firefox Reality, Oculus Browser, Edge и браузер Helio от Magic Leap и другие.

Эта статья начинает серию статей об иммерсивном Интернете. В этом выпуске рассматривается настройка базового приложения WebXR, а также вход в сеанс XR и выход из него. В последующих статьях будет рассмотрен цикл кадров (рабочая лошадка WebXR), особенности дополненной реальности и API-интерфейс WebXR Hit Test — средство обнаружения поверхностей в сеансе AR. Если не указано иное, все, что я рассказываю в этой и последующих статьях, в равной степени применимо как к AR, так и к VR.

Что такое иммерсивный веб?

Хотя мы используем два термина для описания иммерсивного опыта — дополненная реальность и виртуальная реальность, — многие думают о нем в диапазоне от полной реальности до полностью виртуальной, с промежуточной степенью погружения. Буква «X» в XR призвана отразить это мышление, будучи своего рода алгебраической переменной, обозначающей что-либо в спектре иммерсивного опыта.

График, иллюстрирующий спектр визуальных впечатлений от полной реальности до полного погружения.
Спектр захватывающих впечатлений

Примеры иммерсивного опыта включают в себя:

  • Игры
  • Видео 360°
  • Традиционные 2D (или 3D) видеоролики, представленные в захватывающей обстановке.
  • Покупка дома
  • Просмотр продуктов у вас дома перед покупкой
  • Иммерсивное искусство
  • Что-то крутое, о чем еще никто не думал

Концепции и использование

Я объясню несколько основ использования API устройства WebXR. Если вам нужна более подробная информация, чем я предоставил, ознакомьтесь с образцами WebXR Рабочей группы по погружению в Интернет или с постоянно растущими справочными материалами MDN . Если вы знакомы с ранними версиями API устройств WebXR, вам следует просмотреть весь этот материал. Произошли изменения.

Код в этой статье основан на базовом образце Immersive Web Workshop ( демо , исходный код ), но отредактирован для ясности и простоты.

Частью создания спецификации WebXR было уточнение мер безопасности и конфиденциальности для защиты пользователей. Следовательно, реализации должны соответствовать определенным требованиям. Веб-страница или приложение должны быть активными и целенаправленными, прежде чем они смогут запросить у зрителя что-либо конфиденциальное. Веб-страницы или приложения должны обслуживаться через HTTPS. Сам API предназначен для защиты информации, полученной от датчиков и камер, которая необходима ему для работы.

Запросить сеанс

Для входа в сеанс XR требуется жест пользователя. Чтобы получить это, используйте обнаружение функций для проверки XRSystem (через navigator.xr ) и вызовите XRSystem.isSessionSupported() . Имейте в виду, что в Chrome версий 79 и 80 объект XRSystem назывался XR .

В приведенном ниже примере я указал, что мне нужен сеанс виртуальной реальности с типом сеанса 'immersive-vr' . Другими типами сеансов являются 'immersive-ar' и 'inline' . Встроенный сеанс предназначен для представления контента в формате HTML и в основном используется для тизерного контента. Это демонстрирует пример сеанса Immersive AR . Я объясню это в следующей статье.

Узнав, что сеансы виртуальной реальности поддерживаются, я включаю кнопку, позволяющую получить пользовательский жест.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

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

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

Обратите внимание на иерархию объектов в этом коде. Он перемещается из navigator в xr в экземпляр XRSession . В ранних версиях API сценарий должен был запросить устройство перед запросом сеанса. Теперь устройство приобретено неявно.

Войти в сеанс

После получения сессии мне нужно ее запустить и войти в нее. Но сначала мне нужно кое-что настроить. Сеансу необходим обработчик событий onend , чтобы приложение или веб-страница могли быть сброшены при выходе пользователя.

Мне также понадобится элемент <canvas> , чтобы нарисовать мою сцену. Это должен быть XR-совместимый WebGLRenderingContext или WebGL2RenderingContext . Все рисование выполняется с использованием их или фреймворка на основе WebGL, такого как Three.js .

Теперь, когда у меня есть место для рисования, мне нужен источник контента, чтобы рисовать на нем. Для этого я создаю экземпляр XRWebGLLayer . Я связываю его с холстом, вызывая XRSession.updateRenderState() .

Когда я нахожусь в сеансе, мне нужен способ определить, где что находится в виртуальной реальности. Мне понадобится эталонное пространство. Базовое пространство 'local-floor' — это пространство, начало координат которого расположено рядом со зрителем, а ось Y равна 0 на уровне пола и не ожидается перемещения. Существуют и другие типы ссылочных пространств , но это более сложная тема, чем я могу здесь рассмотреть. Я сохраняю ссылочное пространство в переменной, потому что оно мне понадобится, когда я буду рисовать на экране.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Получив ссылочное пространство, я вызываю XRSession.requestAnimationFrame() . Это начало представления виртуального контента, которое выполняется в цикле кадров.

Запуск цикла кадров

Цикл кадра — это бесконечный цикл, управляемый пользовательским агентом, в котором контент неоднократно выводится на экран. Содержимое рисуется в отдельных блоках, называемых кадрами. Последовательность кадров создает иллюзию движения. Для приложений VR частота кадров в секунду может составлять от 60 до 144. AR для Android работает со скоростью 30 кадров в секунду. Ваш код не должен предполагать какую-либо конкретную частоту кадров.

Основной процесс цикла кадра:

  1. Вызовите XRSession.requestAnimationFrame() . В ответ пользовательский агент вызывает XRFrameRequestCallback , определенный вами.
  2. Внутри вашей функции обратного вызова:
    1. Снова вызовите XRSession.requestAnimationFrame() .
    2. Получите позу зрителя.
    3. Передайте («привяжите») WebGLFramebuffer из XRWebGLLayer в WebGLRenderingContext .
    4. Выполните итерацию по каждому объекту XRView , извлекая его XRViewport из XRWebGLLayer и передавая его в WebGLRenderingContext .
    5. Нарисуйте что-нибудь во фреймбуфере.

Оставшаяся часть этой статьи описывает шаг 1 и часть шага 2, настройку и вызов XRFrameRequestCallback . Остальные пункты шага 2 рассматриваются в части II.

Обратный вызов XRFrameRequestCallback

XRFrameRequestCallback определяется вами. Он принимает два параметра: DOMHighResTimeStamp и экземпляр XRFrame . Объект XRFrame предоставляет информацию, необходимую для отображения одного кадра на дисплее. Аргумент DOMHighResTimeStamp предназначен для использования в будущем.

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

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

На этом этапе пришло время нарисовать что-нибудь для зрителя. Это обсуждение второй части. Прежде чем идти туда, позвольте мне показать вам, как завершить сеанс.

Завершить сеанс

Сеанс погружения может завершиться по нескольким причинам, включая завершение вашим собственным кодом посредством вызова XRSession.end() . Другие причины включают отключение гарнитуры или управление ею другим приложением. Вот почему правильное приложение должно отслеживать end событие. Когда это произойдет, отбросьте сеанс и связанные с ним объекты рендеринга. Завершившийся сеанс погружения невозможно возобновить. Чтобы снова войти в режим погружения, моему приложению необходимо начать новый сеанс.

Вспомните раздел «Вход в сеанс» , где во время настройки я добавил обработчик событий onend .

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

Внутри обработчика событий восстановите состояние приложения до того, как пользователь вошел в сеанс.

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

Заключение

Я не объяснил всего, что вам нужно для написания приложения Web XR или AR. Надеюсь, я дал вам достаточно информации, чтобы вы могли самостоятельно разобраться в коде, и достаточно, чтобы начать экспериментировать. В следующей статье я объясню цикл кадров, в котором контент выводится на экран.

Фото JESHOOTS.COM на Unsplash