Несколько основных моментов, которые помогут вам подготовиться к целому спектру иммерсивных впечатлений: виртуальной реальности, дополненной реальности и всему, что между ними.
В Chrome 79 появились возможности для полного погружения в виртуальную реальность. API WebXR Device API обеспечивает поддержку виртуальной реальности, а поддержка дополненной реальности появилась в Chrome 81. Обновление API GamePad расширяет возможности управления в виртуальной реальности. Вскоре эти характеристики будут поддерживать и другие браузеры, включая Firefox Reality, Oculus Browser, Edge и браузер Helio от Magic Leap, и многие другие.
Эта статья открывает серию публикаций об иммерсивном интернете. В этой части рассматривается настройка базового приложения WebXR, а также вход и выход из XR-сессии. В последующих статьях будут рассмотрены цикл кадров (основной элемент работы WebXR), особенности дополненной реальности и API WebXR Hit Test, средство обнаружения поверхностей в AR-сессии. Если не указано иное, все, что я рассматриваю в этой и последующих статьях, в равной степени применимо как к AR, так и к VR.
Что такое иммерсивный интернет?
Хотя для описания иммерсивных впечатлений мы используем два термина — дополненная реальность и виртуальная реальность — многие представляют их как спектр от полной реальности до полной виртуальности, с промежуточными степенями погружения. Буква «X» в аббревиатуре XR призвана отразить это мышление, представляя собой своего рода алгебраическую переменную, обозначающую всё, что находится в спектре иммерсивных впечатлений.

Примерами иммерсивных впечатлений являются:
- Игры
- 360° видео
- Традиционные 2D (или 3D) видеоролики, представленные в иммерсивной обстановке.
- покупка дома
- Осмотрите товары у себя дома перед покупкой.
- Иммерсивное искусство
- Что-то крутое, о чём ещё никто не додумался.
Понятия и применение
Я объясню несколько основных моментов использования WebXR Device API. Если вам требуется более подробная информация, чем та, что я предоставил, ознакомьтесь с примерами WebXR от Immersive Web Working Group или постоянно пополняющимися справочными материалами MDN . Если вы знакомы с ранними версиями WebXR Device API, вам следует бегло просмотреть весь этот материал. Были внесены изменения.
Код в этой статье основан на базовом примере рабочей группы по иммерсивным веб-технологиям ( демо , исходный код ), но отредактирован для большей ясности и простоты.
Частью работы над спецификацией WebXR стала проработка мер безопасности и конфиденциальности для защиты пользователей. Следовательно, реализации должны соответствовать определенным требованиям. Веб-страница или приложение должны быть активны и находиться в фокусе, прежде чем они смогут запрашивать у пользователя какую-либо конфиденциальную информацию. Веб-страницы или приложения должны предоставляться по протоколу HTTPS. Сам API предназначен для защиты информации, получаемой от датчиков и камер, которая необходима ему для функционирования.
Запросить сессию
Для входа в XR-сессию требуется жест пользователя. Чтобы его получить, используйте обнаружение функций для проверки XRSystem (через navigator.xr ) и вызовите метод XRSystem.isSessionSupported() . Обратите внимание, что в версиях Chrome 79 и 80 объект XRSystem назывался XR .
В приведенном ниже примере я указал, что хочу создать сеанс виртуальной реальности с типом сессии 'immersive-vr' . Другие типы сессий — 'immersive-ar' и 'inline' . Сессия 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 кадров в секунду. Ваш код не должен предполагать какую-либо конкретную частоту кадров.
Основной процесс для циклической обработки кадров выглядит следующим образом:
- Вызовите
XRSession.requestAnimationFrame(). В ответ пользовательский агент вызоветXRFrameRequestCallback, который определен вами. - Внутри вашей функции обратного вызова:
- Вызовите
XRSession.requestAnimationFrame()еще раз. - Определите позу зрителя.
- Передайте ('bind')
WebGLFramebufferизXRWebGLLayerвWebGLRenderingContext. - Пройдитесь по каждому объекту
XRView, извлеките егоXRViewportизXRWebGLLayerи передайте его вWebGLRenderingContext. - Нарисуйте что-нибудь в буфере кадра.
- Вызовите
В оставшейся части статьи описывается шаг 1 и часть шага 2, а именно настройка и вызов функции XRFrameRequestCallback . Остальные пункты шага 2 рассматриваются во второй части.
XRFramRequestCallback
Функция 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';
}
Заключение
Я не объяснил всё, что нужно для написания веб-приложения XR или AR. Надеюсь, я дал вам достаточно информации, чтобы вы могли самостоятельно разобраться в коде и начать экспериментировать. В следующей статье я объясню цикл отрисовки кадров, то есть процесс отрисовки контента на экране.