Дополненная реальность: возможно, вы это уже знаете

Если вы уже использовали API устройства WebXR, вы уже почти все сделали.

Джо Медли
Joe Medley

API устройств WebXR появился прошлой осенью в Chrome 79. Как было сказано тогда, реализация API в Chrome находится в стадии разработки. Chrome рад сообщить, что часть работы завершена. В Chrome 81 появились две новые функции:

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

Информацию о тестировании попадания см. в сопутствующей статье «Позиционирование виртуальных объектов в реальных представлениях» . Код в этой статье основан на образце Immersive AR Session ( демо- исходник ) из примеров WebXR Device API рабочей группы Immersive Web.

Прежде чем углубляться в код, вам следует хотя бы один раз воспользоваться примером сеанса Immersive AR . Вам понадобится современный телефон Android с Chrome 81 или более поздней версии.

Чем это полезно?

Дополненная реальность станет ценным дополнением ко многим существующим или новым веб-страницам, позволяя им реализовывать варианты использования AR, не выходя из браузера. Например, это может помочь людям учиться на образовательных сайтах и ​​позволить потенциальным покупателям визуализировать предметы у себя дома во время покупок.

Рассмотрим второй вариант использования. Представьте себе, что вы имитируете размещение виртуального объекта в натуральную величину в реальной сцене. После размещения изображение остается на выбранной поверхности, имеет тот размер, который был бы, если бы реальный элемент находился на этой поверхности, и позволяет пользователю перемещаться вокруг него, а также приближаться к нему или удаляться от него. Это дает зрителям более глубокое понимание объекта, чем это возможно при использовании двухмерного изображения.

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

Запрос сеанса

Запрос на сеанс очень похож на то, что вы видели раньше. Сначала выясните, доступен ли нужный вам тип сеанса на текущем устройстве, вызвав xr.isSessionSupported() . Вместо запроса 'immersive-vr' как раньше, запросите 'immersive-ar' .

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

Как и раньше, это активирует кнопку «Ввести AR». Когда пользователь щелкнет по нему, вызовите xr.requestSession() , также передав 'immersive-ar' .

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

Удобная недвижимость

Вы, наверное, заметили, что в последнем примере кода я выделил две строки. Похоже, что у объекта XRSession есть свойство isImmersive . Это свойство для удобства, которое я создал сам, а не часть спецификации. Я буду использовать его позже, чтобы принять решение о том, что показать зрителю. Почему это свойство не является частью API? Поскольку вашему приложению может потребоваться отслеживать это свойство по-другому, поэтому авторы спецификации решили сохранить API в чистоте.

Вход в сеанс

Вспомните, как выглядел onSessionStarted() в моей предыдущей статье:

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

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

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

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

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

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

 
if (session.isImmersive) {
    removeBackground
();
 
}

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

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

  refSpaceType
= xrSession.isImmersive ? 'local' : 'viewer';
  xrSession
.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession
.requestAnimationFrame(onXRFrame);
 
});

}

Эталонные пространства

Мои предыдущие статьи касались справочных областей. В описываемом мной примере используются два из них, поэтому пришло время исправить это упущение.

Эталонное пространство описывает отношения между виртуальным миром и физической средой пользователя. Это делается путем:

  • Указание начала системы координат, используемой для выражения позиций в виртуальном мире.
  • Указывает, будет ли пользователь перемещаться внутри этой системы координат.
  • Имеет ли эта система координат заранее установленные границы. (В приведенных здесь примерах не используются системы координат с заранее установленными границами.)

Для всех ссылочных пространств координата X обозначает лево и право, Y — вверх и вниз, а Z — вперёд и назад. Положительные значения — вправо, вверх и назад соответственно.

Координаты, возвращаемые XRFrame.getViewerPose() зависят от запрошенного типа ссылочного пространства . Подробнее об этом, когда мы доберемся до цикла кадров. Прямо сейчас нам нужно выбрать тип ссылки, подходящий для дополненной реальности. Опять же, здесь используется мое свойство удобства.

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

 
if (session.isImmersive) {
    removeBackground
();
 
}

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

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

  refSpaceType
= xrSession.isImmersive ? 'local' : 'viewer';
  xrSession
.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession
.requestAnimationFrame(onXRFrame);
 
});
}

Если вы посетили образец сеанса Immersive AR, вы заметили, что изначально сцена статична и совсем не является дополненной реальностью. Вы можете перетаскивать и проводить пальцем по сцене, чтобы перемещаться по сцене. Если нажать «НАЧАТЬ AR», фон пропадет, и вы сможете перемещаться по сцене, перемещая устройство. В режимах используются разные типы ссылочного пространства. Выделенный текст выше показывает, как это выбрано. Он использует следующие типы ссылок:

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

viewer . Чаще всего используется для содержимого, представленного на странице. Это пространство следует за устройством просмотра. При передаче в getViewerPose он не обеспечивает отслеживание и, таким образом, всегда сообщает о позе в источнике, если приложение не изменяет ее с помощью XRReferenceSpace.getOffsetReferenceSpace() . В примере это используется для включения сенсорного панорамирования камеры.

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

Концептуально ничего не меняется по сравнению с тем, что я делал на VR-сессии, описанной в моих предыдущих статьях. Передайте тип ссылочного пространства в XRFrame.getViewerPose() . Возвращаемый XRViewerPose будет относиться к текущему типу справочного пространства. Использование viewer по умолчанию позволяет странице отображать предварительный просмотр контента до того, как будет запрошено согласие пользователя на использование AR или VR. Это иллюстрирует важный момент: встроенный контент использует тот же цикл кадров, что и иммерсивный контент, что сокращает объем кода, который необходимо поддерживать.

function onXRFrame(hrTime, xrFrame) {
  let xrSession
= xrFrame.session;
  xrSession
.requestAnimationFrame(onXRFrame);
  let xrViewerPose
= xrFrame.getViewerPose(refSpaceType);
 
if (xrViewerPose) {
   
// Render based on the pose.
 
}
}

Заключение

В этой серии статей рассматриваются только основы реализации иммерсивного контента в Интернете. Многие другие возможности и варианты использования представлены в примерах API устройств WebXR рабочей группы Immersive Web. Мы также только что опубликовали статью о тестировании попадания , в которой объясняется API для обнаружения поверхностей и размещения виртуальных объектов в реальном виде с камеры. Ознакомьтесь с ними и посмотрите блог web.dev, чтобы узнать больше статей в следующем году.

Фото Дэвида Гранмугена на Unsplash